“九韶杯”河科院程式設計協會第一屆程式設計競賽題目分析以及總結

江上舟搖發表於2022-03-13

還是有很多不足的,模擬思維還需加強,還有一直被詬病的圖論

一:6的個數;

水題,沒有過多的花裡胡哨,手算(不太建議)或者程式碼模擬即可

參考程式碼如下:

 1 #pragma GCC optimize(3)
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 int n=2021, num = 0;
 5 int main()
 6 {
 7     ios::sync_with_stdio(false);
 8     for (register int i = 1; i <= 2021; i++)
 9     {
10         int num1=i;
11         while (num1)
12         {
13             if (num1 % 10==6)num++;
14             num1 /= 10;
15         }
16     }
17     cout<<num;
18     return 0;
19 }

二:小明的作業;

不好意思,錯了,我是弱雞;

三:斐波那契(模擬思維的具體體現)

提供兩種思路

1.常見的gcd寫法,即gcd的遞迴寫法,也有相應的輾轉相除法,不在贅敘;

 1 #pragma GCC optimize(3)
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 int a[100]={0,1,1};
 5 int b[100];
 6 long long  fenzi;
 7 long long  fenmu;
 8 long long  gcd(long long  a,long long  b)//手寫gcd函式 
 9 {
10     if(b==0) return a;
11     return gcd(b,a%b);
12 }
13 int main()
14 {
15     for(register int i=3;i<=18;i++)
16     {
17         a[i]=a[i-1]+a[i-2];
18     }
19     for(int i=1;i<=13;i++)
20     {
21         b[i]=a[i]*a[i+1];//分母 
22     }
23     fenzi=1;//分子 
24     fenmu=1;//分母 
25     for(int i=2;i<=13;i++)
26     {
27         fenzi=fenzi*b[i]+1*fenmu;
28         fenmu=fenmu*b[i];
29         long long  temp=gcd(fenzi,fenmu);//兩者的最大共約數 
30         fenzi=fenzi/temp;//通分 ,不通分的後果就是程式不走或者直接爆 
31         fenmu=fenmu/temp;//通分 
32     } 
33     cout<<fenzi<<"/"<<fenmu<<endl;
34     return 0;
35 } 

還要一種是關於STL庫裡好像是直接能寫一種gcd函式,具體請看這篇https://blog.csdn.net/qq_44731019/article/details/109478391(轉載),然後網上給出的程式碼思路也是和手寫gcd大致的,這個相較於手寫省去了很多麻煩,學到了;

摘自網上程式碼:

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 int main()
 5 {
 6     long long f[14];
 7     f[0]=1;
 8     f[1]=1;
 9     for(int i=2;i<=13;i++)
10     {
11         f[i]=f[i-1]+f[i-2];
12     }
13     long long up=1,down=1;
14     for(int i=1;i<13;i++)
15     {
16         long long x=f[i]*f[i+1];
17         long long k=__gcd(x,down);
18         down*=(x/k);
19         up=up*(x/k)+down/x;
20     }
21     long long k=__gcd(up,down);
22     up/=k;
23     down/=k;
24     cout<<up<<'/'<<down<<endl;
25     return 0;
26 }

四:數列重組;

全排列肯定是少不了了,久違的next_permutation()肯定是要用的,

大體思路即是,在按照字典序的情況下,先判斷是否升序還是降序,並且對他們進行標記,然後滿足了三個開始重新標記,即進行下一輪的升序或者降序判斷,並且在滿足條件的時候加一

參考程式碼如下:

 1 #pragma GCC optimize(3) 
 2 #include<bits/stdc++.h> 
 3 using namespace std;
 4 int a[20] = {2, 3, 3, 3, 5, 6, 6, 7, 7, 8};
 5 int ans;//放結果 
 6 int main(){
 7     ios::sync_with_stdio(false); 
 8     do{//next_permutaion()一般搭配do-while使用 
 9         bool flag1 = false, flag2 = false;//flag1表示之前是否出現遞增,flag2表示之前是否出現遞減
10         int cnt = 0;//計數器 
11         for(register int i = 0;i<9; i++){//為社麼是小於9呢?因為有i+1,那這樣最後一個會越界,然後結果減半 
12             if(a[i + 1] > a[i]){
13                 flag1 = true;
14                 if(flag2){
15                      cnt ++;
16                     flag2 = false;
17                      flag1 = false;//flag1也要,因為當出現分割點後每次要從新的起點開始算,不受之前的區間影響了
18 
19                 }
20 
21             }
22             else if(a[i + 1] < a[i]){
23                 flag2 = true;
24                 if(flag1){
25                     cnt ++;
26                     flag1 = false;
27                     flag2 = false;
28                 }
29 
30             }
31         }
32         if(cnt <= 2) ans ++;
33     }while(next_permutation(a, a + 10));//按字典序排序 
34     cout << ans;
35     return 0;
36 }

五:三角形個數

妥妥的好題,模擬思維的具體體現,這個題我是最後才做的,剛開始確實沒想到是等差數列;不過網上大多數人說用字首和求,我是弱雞,我不會(●ˇ∀ˇ●)

具體思路:

其實是找倒三角和正三角的個數,很不好找的其實

如果三角形的邊長是i

對於大三角形來說,如果正三角形是以1開始,到n-i+1結束的等差數列

而對於倒三角來說,是從1開始,到n-2i+1結束的;

 1 #pragma GCC optimizee(3)
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 const long long  M=1e9+7;
 5 int main()
 6 {
 7     ios::sync_with_stdio(false);
 8     long long d=20210411,n;
 9     long long sumz=0;  
10     for(n=d;n>=1;n--)
11         sumz=(sumz+n*(n+1)/2)%M;
12     long long sumd=0;  
13     for(n=d-1;n>=1;n-=2)
14         sumd=(sumd+n*(n+1)/2)%M;
15     printf("%lld\n",(sumz+sumd)%M);
16     return 0;
17 }

此外,本題特別鳴謝我身旁的zhy同學,如果他不和我說這個題是等差並且一直在堅持這個題,或許我就give up了;

六:字串

沒有什麼特殊的技巧,值得注意的是關於如何接受空格符的問題,這裡有兩種方法:

1.getline函式:http://c.biancheng.net/view/1345.html(轉載)

2.輸入的正則用法:https://blog.csdn.net/weixin_43469047/article/details/83753526(轉載);

不得不說長見識了

七:不會

八:友誼紐帶

唉,bfs我是很不擅長的,主要是用太多了STL關於佇列的操作,我當時都不知道怎麼做出來的,並且我的程式碼和網上標準答案大相徑庭,還是學習大佬的程式碼把

 1 /*1.這題一開始我讀題目了,我以為的是把這些點全部連線起來所需要的最小邊數;
 2     於是我用了並查集,只過了兩個點~
 3 2.後來發現題目是要求找出一個連通塊裡的任意兩點的距離,也就是連通塊的最大長度;
 4     這樣的話我們就可以用BFS暴力搜尋所有節點,找出它們距其他節點的最遠距離`的最大值`;
 5     當一次廣搜之後仍有節點未被訪問的則說明該圖不只有一個連通塊,輸出-1;
 6 */
 7 #include<bits/stdc++.h>
 8 using namespace std;
 9 vector<int>G[2005];
10 int vis[2005];
11 int BFS(int x){
12     memset(vis,0,sizeof(vis));
13     queue<int>q;
14     q.push(x);
15     int ans=0;
16     while(!q.empty()){
17         int f=q.front();
18         q.pop();
19         ans=max(ans,vis[f]);
20         for(int i=0;i<G[f].size();i++){
21             int temp=G[f][i];
22             if(vis[temp]==0){
23                 vis[temp]=vis[f]+1;
24                 q.push(temp);
25             }
26         }
27     }
28     return ans;
29 }
30 int main(){
31     int n,m;
32     cin>>n>>m;
33     for(int i=0;i<m;i++){
34         int a,b;
35         cin>>a>>b;
36         G[a].push_back(b);
37         G[b].push_back(a);
38     } 
39     int ans=0;
40     bool flag=true;
41     for(int j=1;j<=n;j++){
42         ans=max(ans,BFS(j));
43         for(int i=1;i<=n;i++)
44             if(vis[i]==0){
45                 flag=false;break;
46             }
47     }
48     if(flag)
49     cout<<ans<<endl;
50     else cout<<"-1"<<endl;
51     return 0;
52 }

轉載自:https://blog.csdn.net/alpha_xia/article/details/115703564?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~Rate-2.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~OPENSEARCH~Rate-2.pc_relevant_antiscanv2&utm_relevant_index=4;

九:傳送門

這題我知道是克魯斯卡爾啊,我沒板子不會寫,太難了,寒假的時候最小生成樹就不會,主要是圖論太難了;

十:最後一個小時的時光,我當時腦子已經一片混沌了,這題我沒記錯的話應該是直接爆搜了,畢竟我也沒啥技巧了,只能搜了,唉;

思路是:列舉出每種獲勝情況,並且用check函式檢驗

然後接下來就是搜了
利用dfs來搜接下來下的一步棋的所有情況
當x==10是結束條件,其實在某一定程度上很像2n皇后,但又不像;

難度較高,高階的思維模擬題,如果沒有技巧建議深搜,畢竟搜可以混一部分的分數,運氣好的話還可以過

 1 #pragma GCC optimize(3) 
 2 #include<bits/stdc++.h> 
 3 using namespace std;
 4 int p[100];
 5 int n;
 6 int ans;
 7 int check(int u)//檢查函式 
 8 {
 9     if(p[0]+p[4]+p[8]==3*u||p[2]+p[4]+p[6]==3*u)
10      return 1;
11     if(p[0]+p[3]+p[6]==3*u||p[1]+p[4]+p[7]==3*u||p[2]+p[5]+p[8]==3*u) 
12     return 1;
13     if(p[0]+p[1]+p[2]==3*u||p[3]+p[4]+p[5]==3*u||p[6]+p[7]+p[8]==3*u) 
14     return 1;
15     else
16     return 0;
17 }
18 int dfs(int x)//深搜 
19 {
20     if(x==10)//邊界條件 
21     {
22         if(check(1)) return 1;//正常返回 
23         if(check(-1)) return -1;//異常返回,此處也可以用bool判斷 
24         return 0; 
25     }
26     //開始模擬,怎麼這麼多模擬題 
27     int t,lost=0,win=0,d=0;
28     if(x&1) t=1;
29     else t=-1;
30     for(int i=0;i<9;i++)
31     {
32         if(p[i]==0)
33         {
34             p[i]=t;
35             if(check(t)) win++;
36             else
37             {
38                int p=dfs(x+1);
39                 if(p==t)
40                     win++;
41                 else if(p==0) d++;
42                 else lost++;
43             }
44             p[i]=0;
45         }
46     }
47     if(win!=0) 
48     return t;
49     else if(d!=0) 
50     return 0;
51     else 
52     return (-1*t);
53 }
54 int main()
55 {
56     ios::sync_with_stdio(false);
57     int t;
58     cin>>t;
59     while(t--)
60     {
61         ans=0;
62         memset(p,0,sizeof(p));
63         cin>>n;
64         for(int i=1;i<=n;i++)
65         {
66             int x,y;
67             cin>>x>>y;
68             x--;
69             y--;
70             if(i&1) p[x*3+y]=1;//按位與運算,取 2進位制整數 i 的最低位,如果最低位是1 則得1,如果最低位是0 則得0。 奇數 i 的最低位 是1,偶數i 的最低位 是0。 
71             else p[x*3+y]=-1;
72         }   
73     ans=dfs(n+1);
74     if(ans==1) cout<<'X'<<endl;
75     else if(ans==0)
76         cout<<-1<<endl;
77     else cout<<'O'<<endl;
78     }
79     return 0;
80 }

總結:

通過這次模擬賽,很明確的是,對於難題,思維題,較難的模擬題,還有圖論尤其是最小生成樹方面還是有很多的不足

但是也得到了一些經驗:做不出來或者沒思路的時候搜也是一種不錯的選擇;

下一步加強搜尋的優化和訓練,學習一些自己在圖論上知識的空缺,加強模擬題以及思維題的訓練,即使難,多練,也會熟能生巧的;

道阻且長,興則將至,戒驕戒躁,任重道遠,早日成為自己想成為的人。

奔向遠方,加油加油!

相關文章