標籤:c++ 藍橋杯
今天上午參加了第五屆藍橋杯比賽,還是去年的地方,還是去年的考場,不同的是經過了一年的曆練,多了一份坦然與自信。不管最後結果如何,是對自己一年學習的一個小小的交代。ACMER IN HHUC, we never say no.
結果填空
1.
a*a+b*b+c*c=1000;a,b,c均為整數,求一組解中的最小值。暴力的題目,很容易就想到了0,10,30.所以沒多想就填上了0,可是考完發現還可以是負數。。。悲了個劇了,三分就這麼水沒了。。
2.
類似於往年的一道高斯的生日,求距離某一天(yyyy-mm-dd)X天是幾月幾日。因為資料比較小1000,編程反倒麻煩,所以手算了。答案應該是2017-08-05;
3.
說有一個神奇的數字,他的平方與立方各位元字不同而且能把0~9十個數全部用完。求這個數!每年都有這種考察對數的每一位操作的,關鍵還是暴力+每一位元字提取判斷;但是剛上來應該要想到i*i+i*i*i 能表示十位,i是個兩位元,從10到100裡面找。答案好象是69;
代碼填空
4.
輸出一個圖形。大致是將一個字串嵌套到一個框框的正中間。
關鍵代碼是:printf(“%*s%s%*s”); ________________;//輸出最中間的一行
關鍵在於考得知識點很偏,%*s之前沒有接觸到過,知道表示的是將前面的空格填滿,但是不知道該怎麼表示。回來查過之後才知道用法類似於空格佔位。所以正確代碼應該是:
printf("%*s%s%*s",(width-2-strlen(buf))/2," ",buf,width-2-(width-2-strlen(buf))/2," ");
5.
1~9排列組合,一些做分子,一些做分母。求能組成的表示為1/3的組合。題目是用遞迴來做的,遞迴求排列枚舉得出。
關鍵代碼:
{t=x[k];x[k]=x[i];x[i]=t};//完成一次交換
結果填空
6.
原題是發撲克,抽象出來就是1~13各最多有四張,任意挑13張,問最多有幾種組合。最開始聽學長說做藍橋杯只要會深搜就可以了。果然是這樣,以後好幾道題思路也是一致的。深搜遍曆,找到所有可能的情況,保證不重複只要保證後一個數大於等於前一個數就可以了。答案是:3598180
#include <iostream>#include <cstdio>using namespace std;int sum;int used[14];int save[14];void dfs(int num);int main(){ for( int i = 1; i <= 13; i++ ) { used[i]=4; save[i]=0; } dfs(1); printf("%d\n",sum); return 0;}void dfs(int num){ if( num == 14 ) { sum++; return ; } for( int i = 1; i <= 13; i++ ) { if( used[i] != 0 && i >= save[num-1] ) { used[i]--; save[num]=i; dfs(num+1); save[num]=0; used[i]++; } } return ;}
7.
本質是一個環排列問題。有3顆黃色,4顆綠色,5顆紫色(顏色是我編的,無所謂了)珠子,串成一串手鏈。求所有不重複的情況數。環排列的公式我當時忘掉了,或者說壓根沒記住。但是我發現深搜得到的每種情況都會有12種重複,並且很容易想到不會出現逆序的情況。就深搜得到了答案,想一想其實原理也差不多。代碼很簡單,答案為:2310.
程式設計
8.
換飲料的題目,大概意思就是三個空瓶換一瓶飲料。問最多喝幾瓶。之前在藍橋杯官網上做到過,但是這次不能外借。不太習慣,剛開始還很納悶,但是其實對於沒做過的人來說反倒降低了難度。
關鍵代碼:
while( N >= 3 ){ sum+=N-N%3; N=N/3+N%3; } //if( N == 2 ) // sum++; sum+=N;
9.
摞骰子問題。就是說有n個骰子摞在一起,但是有m組情況會使這摞骰子不穩定,所以要避免。比如1 2,所以1和2不能相鄰。輸入n,m;接下來m組資料。輸出所有的可能數。注意每一個對著你的面不同都代表不同的情況,可以旋轉。
一組範例:
輸入:
2 1
1 2
輸出:
544
分析:544=2×4×5×4+4×4×6×4;
這是一道dp,並且因為資料量太大,所以需要用滾動dp。具體資料量我忘記了,100%好象是10^9.因為結果可能數量太大,所以需要對10^9+7模數。
#include <iostream>#include <cstring>#include <cstdio>#define mod 1000000007using namespace std;int N,M;int a,b;int dp[2][7];int m[7][7];long long sum;int main(){ memset(m,0,sizeof(m)); cin>>N>>M; for( int i = 0; i < M; i++ ) { cin>>a>>b; m[a][b]=1; m[b][a]=1; } for( int i = 1; i <= 6; i++ ) dp[0][i]=4; for( int i = 2; i <= N; i++ ) { for( int j = 1; j <= 6; j++ ) { for( int k = 1; k <= 6; k++ ) { if( m[j][k] != 1 ) { dp[1][j]=((dp[1][j])%mod+(dp[0][k]*4)%mod)%mod; } } } for( int j = 1; j <= 6; j++ ) { dp[0][j]=dp[1][j]; dp[1][j]=0; } } for( int i = 1; i <= 6; i++ ) sum=(sum%mod+dp[0][i]%mod)%mod; cout<<sum<<endl; return 0;}
10.
這道題題意很複雜。因為講的不是太清楚,理解了很久。大概抽象出來就是有N個村子,M條道路。現在道路全壞了,需要修路,每個道路的花費是P。但是修路只能從L到R中挑選能對K取餘得到C的道路。每條路都是同時開工的,所以花費的最大時間就是所有這些道路中花費最大的一條。
從題目來看,應該是一道最短路(好像每次都有一道最短路的)。但是在如何鬆弛以及選擇哪種方法之間抉擇了很久。最開始想要用SPFA,但是後來注意到應該是一個多對多的問題,SPFA顯然太複雜了。。。還是Floyed更好一點,哈哈。也就到這種程度了。那現在關鍵是鬆弛條件,其實想一想其實和純Floyed很相似的,但是我們要找的是整條路上的最大的花費時間,而每條路最大的花費時間是等於可以鬆弛的另兩條路的較大的那一個的。類似於Floyed,所以就很簡單了,但是因為是大資料,我也不知道這種想法究竟能過多少,看人品了吧。。。
#include <iostream>#include <cstdio>#include <cstring>#define MAX 5000#define INF 0x7ffffffusing namespace std;int N,M,Q;int x,y,p;int L,R,K,C;int num,res;int m[MAX][MAX];int save[MAX];void Floyed();int main(){ cin>>N>>M>>Q; for( int i = 1; i <= N; i++ ) { for( int j = 1; j <= N; j++ ) { m[i][j]=INF; } } for( int i = 0; i < M; i++ ) { cin>>x>>y>>p; m[x][y]=min(m[x][y],p); m[y][x]=min(m[y][x],p); } Floyed(); for( int i = 0; i < Q; i++ ) { cin>>L>>R>>K>>C; num=0;res=-1; memset(save,0,sizeof(save)); for( int j = L; j <= R; j++ ) { if( j % K == 0 ) { save[num]=j; num++; } } for( int j = 0; j < num; j++ ) for( int k = j; k < num; k++ ) res = max( res,m[save[j]][save[k]]); cout<<res<<endl; } return 0;}void Floyed(){ for( int k = 1; k <= N; k++ ) { for( int i = 1; i <= N; i++ ) { for( int j = 1; j <= N; j++ ) { if( m[i][j] > max(m[i][k],m[k][j]) ) m[i][j] = max(m[i][k],m[k][j]); } } } return ;}
總體覺得這次做得還好,都挺順利的。做到最後一道題是有點急了,因為時間太久了後背冒虛汗。。。。但是回來問到團隊裡的其他人好像都不太理想,晚上聚餐聽他們說的話挺傷感的。不知道自己能在演算法的道路上走多久。改天再單獨寫篇部落格好了。。希望能有機會進入決賽,等待最後的結果吧。
第五屆藍橋杯C++本科A組