鄭州大學2018新生訓練賽第十場題解

  比賽(補題)地址:http://222.22.65.164/problemset.php

  題號爲:4305 —— 4309

  總述:這次新生賽難度偏於平和,但涵蓋方面甚廣,其中一道簽到題是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 (int i = 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 = 2* 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 }

 

   更新得這麼遲實在不好意思,抱歉耽誤大家時間了,QAQ!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章