1. 程式人生 > >2015年4月第六屆藍橋杯c/c++B組省賽試題和個人解答

2015年4月第六屆藍橋杯c/c++B組省賽試題和個人解答

又一年的藍橋杯,好久沒那麼爽快的做題了,昨天上午剛考完藍橋杯,我把題帶出來了。不廢話,上題。

     一、

獎券數目


有些人很迷信數字,比如帶“4”的數字,認為和“死”諧音,就覺得不吉利。
雖然這些說法純屬無稽之談,但有時還要迎合大眾的需求。某抽獎活動的獎券號碼是5位數(10000-99999),要求其中不要出現帶“4”的號碼,主辦單位請你計算一下,如果任何兩張獎券不重號,最多可發出獎券多少張。


請提交該數字(一個整數),不要寫任何多餘的內容或說明性文字。

解答:水題,不說什麼,暴力窮舉

#include <cstdio>
int main()
{	int sum=0;
	for(int i=1;i<10;i++){
		for(int j=0;j<10;j++){
			for(int k=0;k<10;k++){
				for(int l=0;l<10;l++){
					for(int o=0;o<10;o++){
						if(i!=4&&j!=4&&k!=4&&l!=4&&o!=4){
							sum++;
							printf("%d%d%d%d%d\n",i,j,k,l,o);
						}
					}
				}
			}
		}
	}
	printf("%d",sum);
	return 0;
}
54288 答案

二、

星系炸彈


在X星系的廣袤空間中漂浮著許多X星人造“炸彈”,用來作為宇宙中的路標。
每個炸彈都可以設定多少天之後爆炸。
比如:阿爾法炸彈2015年1月1日放置,定時為15天,則它在2015年1月16日爆炸。
有一個貝塔炸彈,2014年11月9日放置,定時為1000天,請你計算它爆炸的準確日期。


請填寫該日期,格式為 yyyy-mm-dd  即4位年份2位月份2位日期。比如:2015-02-19
請嚴格按照格式書寫。不能出現其它文字或符號。

解答:當時時間有限,所以就那exl拉的,答案是2017-08-05.水題



三、三羊獻瑞


觀察下面的加法算式:


      祥 瑞 生 輝
  +   三 羊 獻 瑞
-------------------
   三 羊 生 瑞 氣


(如果有對齊問題,可以參看【圖1.jpg】)


其中,相同的漢字代表相同的數字,不同的漢字代表不同的數字。


請你填寫“三羊獻瑞”所代表的4位數字(答案唯一),不要填寫任何多餘內容。


解答:窮舉題,水體,

#include <cstdio>
int main(){
	int a,b,c,d,e,f,g;
	for(a=1;a<10;a++){
		for(b=0;b<10;b++){
			for(c=0;c<10;c++){
				for(d=0;d<10;d++){
					for(e=1;e<10;e++){
						for(f=0;f<10;f++){
							for(g=0;g<10;g++){
								if(a!=b&&a!=c&&a!=d&&a!=e&&a!=f&&a!=g&&b!=c&&b!=d&&b!=e&&b!=f&&b!=g&&c!=d&&c!=e&&c!=f&&c!=g&&d!=e&&d!=f&&d!=g&&e!=f&&e!=g&&f!=g)
								if(((a*1000+b*100+c*10+d)+(e*1000+f*100+g*10+b))/10==(e*1000+f*100+c*10+b)){
									printf("%d+%d=%d\n",(a*1000+b*100+c*10+d),(e*1000+f*100+g*10+b),(a*1000+b*100+c*10+d)+(e*1000+f*100+g*10+b));
								}
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

答案1085

四、

格子中輸出


StringInGrid函式會在一個指定大小的格子中列印指定的字串。
要求字串在水平、垂直兩個方向上都居中。
如果字串太長,就截斷。
如果不能恰好居中,可以稍稍偏左或者偏上一點。


下面的程式實現這個邏輯,請填寫劃線部分缺少的程式碼。


#include <stdio.h>
#include <string.h>


void StringInGrid(int width, int height, const char* s)
{
int i,k;
char buf[1000];
strcpy(buf, s);
if(strlen(s)>width-2) buf[width-2]=0;

printf("+");
for(i=0;i<width-2;i++) printf("-");
printf("+\n");

for(k=1; k<(height-1)/2;k++){
printf("|");
for(i=0;i<width-2;i++) printf(" ");
printf("|\n");
}

printf("|");

printf("%*s%s%*s",_____________________________________________);  //填空
         
printf("|\n");

for(k=(height-1)/2+1; k<height-1; k++){
printf("|");
for(i=0;i<width-2;i++) printf(" ");
printf("|\n");
}

printf("+");
for(i=0;i<width-2;i++) printf("-");
printf("+\n");
}


int main()
{
StringInGrid(20,6,"abcd1234");
return 0;
}


對於題目中資料,應該輸出:
+------------------+
|                        |
|     abcd1234   |
|                        |
|                        |
+------------------+


(如果出現對齊問題,參看【圖1.jpg】)


注意:只填寫缺少的內容,不要書寫任何題面已有程式碼或說明性文字。

解答:變態的考語法題,估計好多人都栽在上邊了,按一個同學的說法,就是奇門隱技

答案應該是     (width-strlen(s)-2)/2,"",buf,(width-strlen(s)-2)/2,""

五、

九陣列分數


1,2,3...9 這九個數字組成一個分數,其值恰好為1/3,如何組法?


下面的程式實現了該功能,請填寫劃線部分缺失的程式碼。


#include <stdio.h>


void test(int x[])
{
int a = x[0]*1000 + x[1]*100 + x[2]*10 + x[3];
int b = x[4]*10000 + x[5]*1000 + x[6]*100 + x[7]*10 + x[8];

if(a*3==b) printf("%d / %d\n", a, b);
}


void f(int x[], int k)
{
int i,t;
if(k>=9){
test(x);
return;
}

for(i=k; i<9; i++){
{t=x[k]; x[k]=x[i]; x[i]=t;}
f(x,k+1);
_____________________________________________ // 填空處
}
}

int main()
{
int x[] = {1,2,3,4,5,6,7,8,9};
f(x,0);
return 0;
}




注意:只填寫缺少的內容,不要書寫任何題面已有程式碼或說明性文字。


解答:水題把{t=x[k]; x[k]=x[i]; x[i]=t;}複製下來



六、加法變乘法


我們都知道:1+2+3+ ... + 49 = 1225
現在要求你把其中兩個不相鄰的加號變成乘號,使得結果為2015


比如:
1+2+3+...+10*11+12+...+27*28+29+...+49 = 2015
就是符合要求的答案。


請你尋找另外一個可能的答案,並把位置靠前的那個乘號左邊的數字提交(對於示例,就是提交10)。


注意:需要你提交的是一個整數,不要填寫任何多餘的內容。

解答:水題,窮舉

答案16

#include <cstdio>
int main(){
	for(int i=1;i<30;i++){
		for(int j=i+2;j<30;j++){
			if(1225-2*i-1-2*j-1+j*(j+1)+i*(i+1)==2015)printf("%d\n",i);
		}
	}
	return 0;
}
七、

牌型種數


小明被劫持到X賭城,被迫與其他3人玩牌。
一副撲克牌(去掉大小王牌,共52張),均勻發給4個人,每個人13張。
這時,小明腦子裡突然冒出一個問題:
如果不考慮花色,只考慮點數,也不考慮自己得到的牌的先後順序,自己手裡能拿到的初始牌型組合一共有多少種呢?


請填寫該整數,不要填寫任何多餘的內容或說明文字。

一看沒思路,估計搜尋剪枝

八、

移動距離


X星球居民小區的樓房全是一樣的,並且按矩陣樣式排列。其樓房的編號為1,2,3...
當排滿一行時,從下一行相鄰的樓往反方向排號。
比如:當小區排號寬度為6時,開始情形如下:


1  2  3  4  5  6
12 11 10 9  8  7
13 14 15 .....


我們的問題是:已知了兩個樓號m和n,需要求出它們之間的最短移動距離(不能斜線方向移動)


輸入為3個整數w m n,空格分開,都在1到10000範圍內
w為排號寬度,m,n為待計算的樓號。
要求輸出一個整數,表示m n 兩樓間最短移動距離。


例如:
使用者輸入:
6 8 2
則,程式應該輸出:
4


再例如:
使用者輸入:
4 7 20
則,程式應該輸出:
5


資源約定:
峰值記憶體消耗 < 256M
CPU消耗  < 1000ms




請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。


所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。


注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。


提交時,注意選擇所期望的編譯器型別。

解答:程式設計水題,

#include <cstdio>
#include <cstdlib>
using namespace std;
int main(){
	int w,m,n;
	scanf("%d%d%d",&w,&m,&n);
	int mx,nx,ny,my;
	if(m%w==0){
		mx=m/w-1;
		my=w;
	}else{
		mx=m/w;
		my=mx%2==0?m%w:((w-m%w)+1);
	}
	if(n%w==0){
		nx=n/w-1;
		ny=w;
	}else{
		nx=n/w;
		ny=nx%2==0?n%w:((w-n%w)+1);
	}
	//printf("%d %d %d %d \n",mx,my,nx,ny);
	printf("%d",abs(mx-nx)+abs(my-ny));
	return 0;
}

九、

壘骰子


賭聖atm晚年迷戀上了壘骰子,就是把骰子一個壘在另一個上邊,不能歪歪扭扭,要壘成方柱體。
經過長期觀察,atm 發現了穩定骰子的奧祕:有些數字的面貼著會互相排斥!
我們先來規範一下骰子:1 的對面是 4,2 的對面是 5,3 的對面是 6。
假設有 m 組互斥現象,每組中的那兩個數字的面緊貼在一起,骰子就不能穩定的壘起來。 
atm想計算一下有多少種不同的可能的壘骰子方式。
兩種壘骰子方式相同,當且僅當這兩種方式中對應高度的骰子的對應數字的朝向都相同。
由於方案數可能過多,請輸出模 10^9 + 7 的結果。


不要小看了 atm 的骰子數量哦~


「輸入格式」
第一行兩個整數 n m
n表示骰子數目
接下來 m 行,每行兩個整數 a b ,表示 a 和 b 數字不能緊貼在一起。


「輸出格式」
一行一個數,表示答案模 10^9 + 7 的結果。


「樣例輸入」
2 1
1 2


「樣例輸出」
544


「資料範圍」
對於 30% 的資料:n <= 5
對於 60% 的資料:n <= 100
對於 100% 的資料:0 < n <= 10^9, m <= 36




資源約定:
峰值記憶體消耗 < 256M
CPU消耗  < 2000ms




請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。


所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。


注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。


提交時,注意選擇所期望的編譯器型別。


解答:動規dp題,能過60%的點,大資料超時,應該還能繼續優化。帶上滾動陣列

#include <cstdio>
long long dp[2][7];
int x[7][7];
int o[7]={0,4,5,6,1,2,3};
int main(){
	int n,m;
	long long ans=0;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		x[a][b]=1;
		x[b][a]=1;
	}
	for(int i=1;i<7;i++){
		dp[0][i]=4;
	}
	for(int i=1;i<n;i++){
		for(int j=1;j<7;j++){
			dp[i%2][j]=0;
			for(int k=1;k<7;k++){
				if(x[k][o[j]]!=1){
					dp[i%2][j]+=dp[(i-1)%2][k]*4;
					dp[i%2][j]%=1000000007;
				}
			}
		}
	}
	for(int i=1;i<7;i++){
		ans+=dp[(n+1)%2][i];
		ans%=1000000007;
	}
	printf("%lld",ans);
	return 0;
}
十、

生命之樹


在X森林裡,上帝建立了生命之樹。


他給每棵樹的每個節點(葉子也稱為一個節點)上,都標了一個整數,代表這個點的和諧值。
上帝要在這棵樹內選出一個非空節點集S,使得對於S中的任意兩個點a,b,都存在一個點列 {a, v1, v2, ..., vk, b} 使得這個點列中的每個點都是S裡面的元素,且序列中相鄰兩個點間有一條邊相連。


在這個前提下,上帝要使得S中的點所對應的整數的和儘量大。
這個最大的和就是上帝給生命之樹的評分。


經過atm的努力,他已經知道了上帝給每棵樹上每個節點上的整數。但是由於 atm 不擅長計算,他不知道怎樣有效的求評分。他需要你為他寫一個程式來計算一棵樹的分數。


「輸入格式」
第一行一個整數 n 表示這棵樹有 n 個節點。
第二行 n 個整數,依次表示每個節點的評分。
接下來 n-1 行,每行 2 個整數 u, v,表示存在一條 u 到 v 的邊。由於這是一棵樹,所以是不存在環的。


「輸出格式」
輸出一行一個數,表示上帝給這棵樹的分數。


「樣例輸入」
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5


「樣例輸出」
8


「資料範圍」
對於 30% 的資料,n <= 10
對於 100% 的資料,0 < n <= 10^5, 每個節點的評分的絕對值不超過 10^6 。


資源約定:
峰值記憶體消耗 < 256M
CPU消耗  < 3000ms




請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。


所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。


注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。


提交時,注意選擇所期望的編譯器型別。

解答:考試的時候朝著30%的資料去的,正解應該是有什麼資料結構,等做出正解在補充吧,先上個當時考試急忙打出來的30%的解。

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
int n,a[50],max1=0,x[20][20],b[20]={0};
bool check(char *s){
	int o[20],sum=0;
	for(int i=0;i<20;i++){
		o[i]=b[i];
	}
	for(int i=1;i<=n;i++){
		if(s[i]=='0'){
			for(int l=0;l<n;l++){
				if(x[i][l]!=0)
				o[l]--;
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(s[i]=='0')o[i]--;
	}
	for(int i=1;i<n;i++){
		if(s[i]=='1'){
			if(o[i]>0){
			}else{
				return false;
			}
		}else{
			
		}
	}
	for(int i=0;i<=n;i++){
		if(o[i]>0){
			sum+=a[i];
		}
	}
	if(sum>max1)max1=sum;
	return true;
}
void f(int x,int sum,char *s){
	if(x>=n){
	check(s);
	}else{
		f(x+1,sum+a[x],strcat(s,"1"));
		s[x+1]=0;
		f(x+1,sum,strcat(s,"0"));
		s[x+1]=0;
	}
}
int main(){
	scanf("%d",&n);
	char s1[60]=" ";
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=0;i<n-1;i++){
		int q,p;
		scanf("%d%d",&q,&p);
		x[q][p]=1;
		x[p][q]=1;
		b[q]++;
		b[p]++;
	}
	f(0,0,s1);
	printf("%d",max1);
	return 0;
}