2015年4月第六屆藍橋杯c/c++B組省賽試題和個人解答
又一年的藍橋杯,好久沒那麼爽快的做題了,昨天上午剛考完藍橋杯,我把題帶出來了。不廢話,上題。
一、
獎券數目
有些人很迷信數字,比如帶“4”的數字,認為和“死”諧音,就覺得不吉利。
雖然這些說法純屬無稽之談,但有時還要迎合大眾的需求。某抽獎活動的獎券號碼是5位數(10000-99999),要求其中不要出現帶“4”的號碼,主辦單位請你計算一下,如果任何兩張獎券不重號,最多可發出獎券多少張。
請提交該數字(一個整數),不要寫任何多餘的內容或說明性文字。
解答:水題,不說什麼,暴力窮舉
54288 答案#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; }
二、
星系炸彈
在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;
}