鄭州大學2018新生訓賽第十場題解
總述:這次新生賽難度偏於平和,但涵蓋方面甚廣,其中一道簽到題是c語言題,並且有兩道是hdu一百題的原題,一道簡單的最小生成樹,唯一“有些難度”的應該是一道數論題(畢竟本來自己就是搞數學的)。
A.沙漠駱駝
這是一道經典的遞推問題,原型為HDU 2044的“一隻小蜜蜂…”。思路很簡單,以第5個沙丘為例,到達第五個沙丘的方式有兩種:從第3個向 右走,或從第4個向右上走。設dp[ i ]為從第一個沙丘走到第i個的路徑數,我們容易得到遞推方程:
dp[5] = dp[4] + dp[3]
那麼依此類推,得到一般的遞推方程:
dp[ i ] = dp[ i-1 ] + dp[ i-2 ]
而從第a個到第b個,則可以簡化為第1個到第b-a個。
1 ll f[100]; 2 3 void init() { 4 f[1] = f[2] = 1; 5 for (int i = 3; i < 100; i++) { 6 f[i] = f[i - 1] + f[i - 2]; 7 } 8 } 9 10 int main() { 11 init(); 12 13 int t; 14 scanf("%d", &t); 15 int a, b; 16 while (t--) {17 scanf("%d%d", &a, &b); 18 printf("%lld\n", f[b - a + 1]); 19 } 20 21 return 0; 22 }
B.爐石傳說真好玩!
水題,原題是 HDU 2052 的 “Picture”,直接放程式碼:
1 int main() { 2 int n, m; 3 while (~scanf("%d%d", &n, &m)) { 4 putchar('+'); 5 for (inti = 0; i < n; i++) putchar('-'); 6 putchar('+'); 7 putchar('\n'); 8 for (int i = 0; i < m; i++) { 9 putchar('|'); 10 for (int j = 0; j < n; j++) { 11 putchar(' '); 12 } 13 putchar('|'); 14 putchar('\n'); 15 } 16 putchar('+'); 17 for (int i = 0; i < n; i++) putchar('-'); 18 putchar('+'); 19 putchar('\n'); 20 putchar('\n'); 21 } 22 23 return 0; 24 }
C.加油啊!奧托大人!
Emmm,這是一道裸的Kruskal,不理解的大家可以搜尋一下,不想搜的也可以等資料結構老師講,2333.
這道題的原題是 HDU 1863 的 “ 暢通工程”。
程式碼如下:
1 struct Edge { 2 int from, to, w; 3 4 Edge(int from = 0, int to = 0, int w = 0): 5 from(from), to(to), w(w) {} 6 7 bool operator < (const Edge &rhs) const { 8 return w < rhs.w; 9 } 10 } edge[MAXEDGE]; 11 12 int parents[MAXVERTEX]; 13 int vertices, edges; 14 15 void init() { 16 for (int i = 1; i < MAXVERTEX; i++) { 17 parents[i] = i; 18 } 19 } 20 21 int find(int x) { 22 if (parents[x] == x) { 23 return x; 24 } else { 25 return parents[x] = find(parents[x]); 26 } 27 } 28 29 bool unite(int x, int y) { 30 x = find(x); 31 y = find(y); 32 if (x == y) { 33 return true; 34 } else { 35 parents[y] = x; 36 } 37 return false; 38 } 39 40 int kruskal() { 41 init(); 42 sort(edge, edge + edges); 43 int ans = 0, counter = 1; 44 for (int i = 0; i < edges; i++) { 45 if (unite(edge[i].from, edge[i].to)) { 46 continue; 47 } else { 48 ans += edge[i].w; 49 counter++; 50 } 51 if (counter >= vertices) { 52 break; 53 } 54 } 55 if (counter >= vertices) { 56 return ans; 57 } else { 58 return -1; 59 } 60 } 61 62 int main() { 63 int u, v, w; 64 65 while (~scanf("%d%d", &edges, &vertices)) { 66 if (edges == 0) break; 67 for (int i = 0; i < edges; i++) { 68 scanf("%d%d%d", &u, &v, &w); 69 edge[i] = Edge(u, v, w); 70 } 71 72 int ans = kruskal(); 73 if (ans == -1) { 74 printf("?\n"); 75 } else { 76 printf("%d\n", ans); 77 } 78 } 79 80 return 0; 81 }
D.大家快來%啊!
這。。。簽到題就不用講,也不用放程式碼了吧。
唯一需要注意的是純c選手輸出時需要將%轉義。
E.R.I.P.
根據算數基本定理,任何一個自然數都可以唯一地分解為若干個素數的乘積,如果我們列出這個數所有的質因數,並寫成冪的乘積的形式,則稱其為標準素因數分解式:
比如:對於120,120 = 2*2*2*3*5,寫成標準素因數分解式就是:
120 = 23 * 31 * 51
那麼我們就可以輕易地得到 120 因子個數:所有冪次+1的乘積
也就是: ( 3 + 1 ) * ( 1 + 1 ) * ( 1 + 1 ) = 16
.....在此證明過程不再贅述
知道了這些,我們來考慮讓一個數因子個數擴大到二倍(我們稱其為一次“擴充套件”)的 “ 費用 ” :
我們可以將總的費用寫為素因子冪的乘積的形式。
考慮這樣實現:將總費用維護為一個堆(為什麼要維護成堆?請認真思考),每個素因子的費用都儲存在一個含有“ 底數,指數,值 ”的結構體中。
初始時堆中沒有元素,通過不斷進行“ 擴充套件 ”,逐漸向堆中增加元素,直到因子個數符合要求(500500)。
那麼 最後每一個結構體中的值再除以底數(為什麼要除以底數?請認真思考) 的乘積就是總的費用。
在考慮操作方法,不外乎有兩種:
1、擴充套件一個新的(指數為0)的素因子(比如說取了 2),並標記為“新素數”(以待後用)。
同時對這個素因子的費用進行更新 2(0+1)->(1 + 1)
2、在堆中取擴充套件費用最小的素數,進行擴充套件(更新其指數),同時更新其費用。
如果這個素數是一個“新素數”,那麼我們從打好的素數表中,取下一個素數(比如說取了2)進堆,將其指數初始化為0。
下邊來看一下程式碼實現:
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int MAXN=600000,curnum=0; 5 bool vis[10000000]; 6 vector<int> sushu; 7 int cursushu=0; 8 struct node{ 9 int dishu; 10 int zhishu; 11 ll zhi; 12 13 }; 14 bool operator<(node a,node b) 15 { 16 return a.zhi>b.zhi; 17 } 18 19 priority_queue<node> dui; 20 ll ans=1; 21 22 void dabiao(){ 23 for(ll i=2;;i++){ 24 if(!vis[i]){ 25 sushu.push_back(i); 26 } 27 if(sushu.size()>500500){ 28 break; 29 } 30 for(ll j=i*i;j<10000000;j+=i){ 31 vis[j]=true; 32 } 33 } 34 } 35 void addnew(int x){ 36 node p; 37 p.dishu=sushu[x]; 38 p.zhishu=1; 39 p.zhi=p.dishu; 40 dui.push(p); 41 } 42 43 44 void update_old_node(node tmp){ 45 node a; 46 a.dishu=tmp.dishu; 47 a.zhishu=tmp.zhishu*2; 48 a.zhi=1; 49 for(int i=0;i<a.zhishu;i++){ 50 a.zhi*=a.dishu; 51 } 52 dui.push(a); 53 } 54 55 void act(){ 56 node tmp=dui.top(); 57 dui.pop(); 58 if(tmp.dishu==sushu[cursushu-1]){ 59 addnew(cursushu++); 60 update_old_node(tmp); 61 } 62 else{ 63 update_old_node(tmp); 64 } 65 } 66 67 int main() 68 { 69 cout<<"Input N:"<<endl; 70 int n; 71 cin>>n; 72 dabiao(); 73 addnew(cursushu++); 74 for(int i=0;i<n;i++) 75 act(); 76 while(!dui.empty()){ 77 ans*=(dui.top().zhi/dui.top().dishu%500500507); 78 ans%=500500507; 79 dui.pop(); 80 } 81 cout<<ans; 82 }