ZAFU 新生賽題解


一篇遲到的題解,本以為大家興趣不大,但是有同學問了,本人覺得還是應該寫一下。

 

T醬和他的數學題

 

要求判斷末尾有多少個0

我們分析一下就可以知道0只能是來自2 和 5 的乘積。

對於每一個數字我們只需要去判斷可以分解出多少個2和5就可以,其中5的出現次數一定會小於2的出現次數。

由於是階乘的階乘

所以我們只需要暴力一遍,維護5出現次數的前綴和的前綴和就可以了

 

 1 #include <stdio.h>
 2 int cal(int x)
 3 {
 4     int res = 0;
 5     while(x)
 6     {
 7         if(x%5) break;
 8         x /= 5;
 9         res++;
10     }
11     return res;
12 }
13 int main()
14 {
15     long long res, tmp;
16     int n;
17     while(scanf("%d", &n) != EOF)
18     {
19         res = tmp = 0;
20         for(int i = 1; i <= n; i++)
21         {
22             tmp += cal(i);
23             res += tmp;
24         }
25         printf("%lld\n", res);
26     }
27 }

 

Vic和騎士

 

自己手推一下 n = 4 和n = 5的情況, 就會發現規律,只要RB交錯排列就可以

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 
 7 int main()
 8 {
 9     int T, n, ca = 0;
10     while(scanf("%d", &n) != EOF)
11     {
12         for(int i = 1; i <= n; i++)
13         {
14             if(i%2) 
15                 for(int j = 1; j <= n; j++)
16                     if(j%2) putchar('B');
17                     else putchar('R');
18             if(i%2==0) 
19                 for(int j = 1; j <= n; j++)
20                     if(j%2) putchar('R');
21                     else putchar('B');
22                     
23             putchar('\n');
24         }
25         putchar('\n');
26     }
27     
28 }

 

 

Vic與水題

 

根據題目輸出就可以, 但是我們提交的輸出樣例顯示有點問題,在題面里也說明了

 

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     int T, n, flag;
 6     cout<<"#include<stdio.h>"<<endl;
 7     cout<<"int main()"<<endl;
 8     cout<<"{"<<endl;
 9     cout<<"int n;"<<endl;
10     cout<<"n = 10;"<<endl;
11     cout<<"printf(\"%d\", n);"<<endl;
12     cout<<"return 0;"<<endl;
13     cout<<"}";
14 }

 

 

保護牛奶

 

對於這一題,我們可以發現,牛奶被放成了一圈,並且只能取連續的。

貪心策略是利用圓的對稱性來反制對手,所以只有當數量為1 或 2 或 3 時, 先手才贏的機會

 

 

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int main()
 5 {
 6     int T, n, flag;
 7     while(scanf("%d", &T) != EOF)
 8     {
 9         while(T--)
10         {
11             scanf("%d", &n);
12             if(n<=3&&n>=1) cout<<"milk will die!!!"<<endl;
13             else cout<<"milk is alive!!!"<<endl;
14         }
15         
16     }
17     
18 }

 

當老板

 

這個題目是一個二分題,但是相對於傳統的二分,我們需要計算上界或者下界來保證二分的順利進行.

 

講一下二分的思路,主要是check比較難

 

對於check的值  我們假設是X,每一個員工的可接受的工資是[Li, Ri]

那么對於Li>X 的員工只能是讓他排在中位數的右邊

對於Ri<X的員工只能是讓他排在中位數的左邊

然后剩下的我們進行最優分配,如果左邊此時還沒達到要求人數的一半,那么應該補足左邊,這些人發放最小工資,右邊的人則是發放X的工資。最后判讀這樣的分配下花費是否夠用可以。

 

具體看代碼吧

 

 1 #include <stdio.h>
 2 #include <cstring>
 3 #include <vector>
 4 #include <set>
 5 #include <algorithm>
 6 using namespace std;
 7 struct node
 8 { 
 9     int l, r;
10     bool operator < (struct node a)
11     {
12         return l < a.l;
13     }
14 }a[200009];
15 typedef long long ll;
16 int T, n, l, r, mid;
17 ll sum;
18 bool check(int x)
19 {
20     vector <struct node> ve;
21     ve.clear();
22     int num = 0;
23     ll res = 0;
24     for(int i = 1; i <= n; i++)
25         if(a[i].r<x) 
26         {
27             res += a[i].l;
28             num++;
29         }
30         else if(a[i].l>x) 
31         {
32             res += a[i].l;
33         }else ve.push_back(a[i]);
34     
35     if(num>=n/2+1) return false;
36     
37     int size = ve.size();
38     
39     for(int i = 0; i < size; i++)
40     if(num<n/2)
41     {
42         res += ve[i].l;
43         num++;
44     }else res += x;
45     
46     return res <= sum;
47 }
48 
49 int main()
50 {
51     scanf("%d", &T);
52     while(T--)
53     {
54         scanf("%d %lld", &n, &sum);
55         for(int i = 1; i <= n; i++)
56         scanf("%d %d", &a[i].l, &a[i].r);
57     
58         r = 1e9;
59         
60         sort(a+1, a+1+n);
61         l = a[n/2+1].l; 
62     //    printf("%d %d\n", l, r);
63         while(l<=r)
64         {
65             mid = (l+r) / 2;
66             if(check(mid))
67             {
68                 if(!check(mid+1)) break;
69                 l = mid+1;
70             }else r = mid - 1;
71         }
72         
73         printf("%d\n", mid);
74     }
75 }

 

 

滴答滴答

 

這是一個暴力模擬的題目,具體的只需要按題意敲就可以,但是比較難處理的是涉及到了大數,我們用數組模擬一下就可以了,考慮到新生賽的難度,所以還是比較好處理的

 

 

 1 #include <stdio.h>
 2 #include <cstring>
 3 #include <string.h>
 4 const int N = 2e5+10;
 5 char s[N];
 6 int res[N];
 7 int main()
 8 {
 9     int T, len, pos, num, flag;
10     scanf("%d", &T);
11     while(T--)
12     {
13         scanf("%s", s+1);
14         len = strlen(s+1);
15         num = pos = 0;
16         s[len+1] = '*';
17         for(int i = 1; i <= len;)
18         {
19             if(s[i]=='d'&&s[i+1]=='a')
20             {
21                 flag = 0;
22                 i = i + 2;
23                 for(int j = 1; j <= 3 && i <= len; i++, j++)
24                 if(s[i]<='9'&&s[i]>='0')
25                 {
26                     res[++pos] = s[i] - '0';
27                     flag = 1;    
28                 } 
29                 if(flag) num++;
30             }else if(s[i]=='d'&&s[i+1]=='i')
31             {
32                 flag = 0;
33                 i = i + 2;
34                 for(int j = 1; j <= 1 && i <= len; i++, j++)
35                 if(s[i]<='9'&&s[i]>='0')
36                 {
37                     res[++pos] = s[i] - '0';
38                     flag = 1;    
39                 } 
40                 if(flag) num++;
41             }else i++;
42         }
43         res[pos] += num;
44         for(int i = pos; i >= 1; i--)
45         {
46             res[i-1] += res[i] / 10;
47             res[i] %= 10;
48         }
49         flag = 0;
50         for(int i = 0; i <= pos; i++)
51         {
52             if(res[i]) flag = 1;
53             if(flag) printf("%d", res[i]);
54         }
55         if(flag) printf("\n");
56         else printf("0\n");
57     }
58 }

 

 

取石子游戲

 

這是一個大三學長出的防AK題,只要了解SG函數,那么恭喜你,你離AC只有半步之遙了,由於SG函數的時間復雜度是N^2 , 所以肯定要優化,其實我們觀察SG函數可以直接得出一個規律,然后這題就AC了。

 

 1 #include <stdio.h>
 2 int cal(int x)
 3 {
 4     for(int i = 0; ; i++)
 5         if((1<<i) > x) return i % 3;
 6         
 7 }
 8 int main()
 9 {
10     int T, n, x, res;
11     scanf("%d", &T);
12     while(T--)
13     {
14         scanf("%d", &n); res = 0;
15         for(int i = 1; i <= n; i++)
16         {
17             scanf("%d", &x);
18             res ^= cal(x);
19         }
20         if(res) printf("first\n");
21         else printf("second\n");
22     }
23 }

 

 

題目夠簡單嗎

 

簽到題,讀入然后判斷數組里面有沒有1就可以了

 

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int T, n, flag;
 5     while(scanf("%d", &T) != EOF)
 6     {
 7         while(T--)
 8         {
 9             scanf("%d", &n);
10             flag = 0;
11             int x;
12             for(int i = 1; i <= n; i++)
13             {
14                 scanf("%d", &x);
15                 if(x) flag = 1;
16             }
17             if(flag) printf("hard\n");
18             else printf("easy\n");
19         }
20         
21     }
22 }

 

 

 

推恩令

 

 

又是來自大三學長的防Ak題,總的思想是二分。

 

首先我們對題目分析后,我們可以將題目轉化為有一個全為0的數列,第i我們可以把數列連續顏色的地方變成i然后問我們有多少種方法可以讓原始數列變成輸入的數列。

 

 1 #include <stdio.h>
 2 typedef long long ll;
 3 ll ans[509][509];
 4 const ll MOD = 292929;
 5 int a[509];
 6 void init(int n)
 7 {
 8     for(int i = 1; i <= n; i++)
 9         for(int j = i; j <= n; j++)
10         ans[i][j] = -1;
11 }
12 ll dfs(int l, int r)
13 {
14     if(l>r) return 1;
15     if(ans[l][r]!=-1) return ans[l][r];
16     ll lans = 0, rans = 0;
17     int pos = l, minn = a[l];
18     for(int i = l+1; i <= r; i++)
19     if(a[i] < minn)
20     {
21         minn = a[i]; pos = i;
22     }
23     for(int i = l; i <= pos; i++)
24     lans = (lans + dfs(l,i-1) * dfs(i, pos-1) % MOD) % MOD;
25     
26     for(int i = pos+1; i <= r+1; i++)
27     rans = (rans + dfs(pos+1, i-1) * dfs(i, r) % MOD) % MOD;
28     
29 //    printf("%d %d --- %lld %lld\n", l, r, lans * rans + 1);
30     return ans[l][r] = lans * rans % MOD; 
31 }
32 int main()
33 {
34     int T, n;
35     scanf("%d", &T);
36     while(T--)
37     {
38         scanf("%d", &n);
39         init(n);
40         for(int i = 1; i <= n; i++) scanf("%d", a+i);
41         printf("%lld\n", dfs(1, n));
42     }
43 }

 

        

 

五等分的ACM

 

題意模擬就可以了

 

 

 1 #include <stdio.h>
 2 int cal(int n)
 3 {
 4     int res = 0;
 5     while(n)
 6     {
 7         int tmp = n % 10;
 8         res += tmp * tmp * tmp  * tmp * tmp;
 9         n /= 10;
10     }
11     return res;
12 }
13 int main()
14 {
15     int T, n;
16     scanf("%d", &T);
17     while(T--)
18     {
19         scanf("%d", &n);
20         if(n==cal(n)) printf("YES\n");
21         else printf("NO\n");
22     }
23 }

 

 

找找zyh

 

分析幾個樣例

 

我們定義numz , numy , numh 為以z y h結尾的前綴的當前出現次數

 

那么最終的答案就是numh

 

 轉移方程也很好理解, 分別是

 當當前字符為  z    時 Numz++;

 當當前字符為  y   時 numy += numz

 當當前字符為  h  時 numh += numy

 

 

                                      

字符判斷

 

 


 

對於這三個樣例  我們可以觀察到如果用塗色法去塗這幾個字母,A需要兩次, B需要三次, C需要一次 (需要全部塗滿)。

塗色法可以用dfs處理

需要特殊處理的是,在讀入后要在周圍添一圈留白,不然可能出現留白需要塗多次的情況,這個我們可以在讀入的時候就預留出空間。

 

 1 #include <stdio.h>
 2 #include <cstring>
 3 char s[50][50] = {0};
 4 int move[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
 5 void dfs(int x, int y)
 6 {
 7     s[x][y] = '*';
 8     int tx, ty;
 9     for(int i = 0; i < 4; i++)
10     {
11         tx = x + move[i][0];
12         ty = y + move[i][1];
13         if(tx<0 || tx>49 || ty<0 || ty>49) continue;
14         if(s[tx][ty]=='*') continue;
15     //    printf("goto %d %d\n", tx, ty);
16         dfs(tx, ty);
17     }
18 }
19 int main()
20 {
21     
22     int time = 0, n;
23     while(gets(s[1]) != NULL)
24     {
25         time = 0;
26         if(strlen(s[1]) == 0) continue;
27         n = 1;
28         for(int i = 2; ; i++)
29         {
30             gets(s[i]);
31             if(strlen(s[i])==0) break;
32             n++;
33         }
34         
35     //    for(int i = 1; i <= n; i++)
36     //    puts(s[i]);
37         
38         for(int i = 0; i <= 49; i++)
39             for(int j = 0; j <= 49; j++)
40             {
41                 if(s[i][j]!='*') 
42                 {
43                     dfs(i, j);
44                     time++;
45                 }
46             }
47             
48     //    printf("%d\n", time);
49             
50         if(time==1) printf("C\n");
51         else if(time==2) printf("A\n");
52         else printf("B\n");
53             
54         memset(s, 0, sizeof(s));
55     }
56     return 0;
57 }

 

 

足球經理

 

利用二維數組讀入后,我們對於每一個隊暴力模擬,計算分數就可以了

計算完分數判斷最大值,然后看有沒有兩個隊分數一樣就可以

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 int res[120][120];
 6 struct node
 7 {
 8     int score, id;
 9     bool operator < (struct node a)
10     {
11         return score > a.score;
12     }
13 }a[120];
14 
15 int main()
16 {
17     int T, n;
18     while(scanf("%d", &T) != EOF)
19     {
20         while(T--)
21         {
22             scanf("%d", &n);
23             for(int i = 1; i <= n; i++)
24                 for(int j = 1; j <= n; j++)
25                 scanf("%d", &res[i][j]);
26             
27             for(int i = 1; i <= n; i++)
28             {
29                 a[i].id = i;
30                 a[i].score = 0;
31                 for(int j = 1; j <= n; j++)
32                 {
33                     if(i==j) continue;
34                     if(res[i][j] > res[j][i]) a[i].score += 3;
35                     else if(res[i][j]==res[j][i]) a[i].score += 1;
36                 }
37             }
38             a[n+1].score = -1;
39             sort(a+1, a+1+n);
40             if(a[1].score != a[2].score) printf("%d\n", a[1].id);
41             else printf("yep!\n");
42         }
43     }
44     
45 }

 

        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM