1.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",(11分)); //填空 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-2-strlen(s))/2,"%20",s,(width-2-strlen(s))/2,"%20"
%*s,%*d......等輸出格式,舉個例子,比較好說明一下:
printf("%*s",5,"123"),執行一下,這條語句,輸出##123(#代表一個空格)類似于%5d%20這樣的狀況,這里*被常量5代替,用于控制最小字符寬度,主要是針對,最小字符寬度未知的情況,當然*可以對應整型變量
2.
1,2,3...9%20這九個數字組成一個分數,其值恰好為1/3,如何組法?
下面的程序實現了該功能,請填寫劃線部分缺失的代碼。
#include%20<stdio.h>void%20test(int%20x[]){ int%20a%20=%20x[0]*1000%20+%20x[1]*100%20+%20x[2]*10%20+%20x[3]; int%20b%20=%20x[4]*10000%20+%20x[5]*1000%20+%20x[6]*100%20+%20x[7]*10%20+%20x[8]; if(a*3==b)%20printf("%d%20/%20%d/n",%20a,%20b);}void%20f(int%20x[],%20int%20k){ int%20i,t; if(k>=9){ test(x); return; } for(i=k;%20i<9;%20i++){ {t=x[k];%20x[k]=x[i];%20x[i]=t;} f(x,k+1); (13分);//%20填空處 }} int%20main(){ int%20x[]%20=%20{1,2,3,4,5,6,7,8,9}; f(x,0); return%200;}此題主要理解生成全排列的函數3.獎券數目(結果填空) (3分)
有些人很迷信數字,比如帶“4”的數字,認為和“死”諧音,就覺得不吉利。%20雖然這些說法純屬無稽之談,但有時還要迎合大眾的需求。某抽獎活動的獎券號碼是5位數(10000-99999),要求其中不要出現帶“4”的號碼,主辦單位請你計算一下,如果任何兩張獎券不重號,最多可發出獎券多少張。
請你計算一共有多少種可能的方案。
輸入格式:
無輸入
輸出格式:
在一行內輸出一個整數,代表最多可發獎券數目,不要寫任何多余的內容或說明性文字。
輸出樣例:123
法一:利用排列組合做,8*9*9**9*9=52488//法二:代碼#include%20<cstdio>#include%20<iostream>int%20main(){ int%20sum=0; for(int%20i=1;i<=9;i++){ for(int%20j=0;j<=9;j++){ for(int%20t=0;t<=9;t++){ for(int%20a=0;a<=9;a++){ for(int%20b=0;b<=9;b++){ if(i!=4&&j!=4&&t!=4&&a!=4&&b!=4) sum++; } } } } } printf("%d/n",sum); return%200;}//524884.星系炸彈(結果填空) (5分)在X星系的廣袤空間中漂浮著許多X星人造“炸彈”,用來作為宇宙中的路標。%20每個炸彈都可以設定多少天之后爆炸。%20比如:阿爾法炸彈2015年1月1日放置,定時為15天,則它在2015年1月16日爆炸。%20有一個貝塔炸彈,2014年11月9日放置,定時為1000天,請你計算它爆炸的準確日期。
輸入格式:
無輸入
輸出格式:
請在一行內輸出該日期,格式為%20yyyy-mm-dd%20即4位年份2位月份2位日期。比如:2015-02-19%20請嚴格按照格式書寫。不能出現其它文字或符號。
//法一:查日歷%20得2017-08-05//法二:Excel//法三:計算器的計算日期功能//法四:代碼#include%20<cstdio>#include%20<cstring>int%20judge(int%20year){ if(year%4==0&&year%100!=0||year%400==0)//判斷閏年 return%20366; return%20365;}int%20main(){ int%20year,month,day=1000-52;//從2015年開始算 int%20m[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}}; for(year=2015;day/judge(year);year++) day-=judge(year); int%20loc=judge(year)-365; for(month=1;day/m[loc][month];month++) day-=m[loc][month]; printf("%04d-%02d-%02d/n",year,month,day); return%200;}5.觀察下面的加法算式:
(如果有對齊問題,可以參看【圖1.jpg】) 
其中,相同的漢字代表相同的數字,不同的漢字代表不同的數字。
請你填寫“三羊獻瑞”所代表的4位數字(答案唯一),不要填寫任何多余內容。
//法一:八重循環//法二:先生成全排列#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;int main(){ int a[10]={0,1,2,3,4,5,6,7,8,9}; do{//用全排列前8位 if(a[0]&&a[4]){ int num1=a[0]*1000+a[1]*100+a[2]*10+a[3]; int num2=a[4]*1000+a[5]*100+a[6]*10+a[1]; int num3=a[4]*10000+a[5]*1000+a[2]*100+a[1]*10+a[7]; if(num1+num2==num3){ cout<<num2<<endl; break; } } }while(next_permutation(a,a+10)); return 0;}//10856.加法變乘法(結果填空) (17分)我們都知道:1+2+3+ ... + 49 = 1225 現在要求你把其中兩個不相鄰的加號變成乘號,使得結果為2015
比如: 1+2+3+...+10 · 11+12+...+27 · 28+29+...+49 = 2015 就是符合要求的答案
請你尋找另外一個可能的答案,并把位置靠前的那個乘號左邊的數字提交(對于示例,就是提交10)。
#include <cstdio>#include <cstring>int main(){ int sum; for(int i=1;i<=46;i++){//i,j均為第幾個+號 for(int j=i+2;j<=48;j++){ sum=0; for(int t=1;t<i;t++){ sum+=t; } sum=sum+i*(i+1); for(int t=i+2;t<j;t++){ sum+=t; } sum=sum+j*(j+1); for(int t=j+2;t<=49;t++){ sum+=t; } if(sum==2015&&i!=10){ printf("%d/n",i); return 0; } } } return 0;} 7.牌型種數(結果填空) (21分)小明被劫持到X賭城,被迫與其他3人玩牌。 一副撲克牌(去掉大小王牌,共52張),均勻發給4個人,每個人13張。 這時,小明腦子里突然冒出一個問題: 如果不考慮花色,只考慮點數,也不考慮自己得到的牌的先后順序,自己手里能拿到的初始牌型組合一共有多少種呢?
//法一:暴力#include <cstdio>#include <cstring>int main(){ int sum=0; for(int a=0;a<=4;a++){ for(int b=0;b<=4;b++){ for(int c=0;c<=4;c++){ for(int d=0;d<=4;d++){ for(int e=0;e<=4;e++){ for(int f=0;f<=4;f++){ for(int g=0;g<=4;g++){ for(int h=0;h<=4;h++){ for(int i=0;i<=4;i++){ for(int j=0;j<=4;j++){ for(int k=0;k<=4;k++){ for(int l=0;l<=4;l++){ for(int m=0;m<=4;m++){ if(a+b+c+d+e+f+g+h+i+j+k+l+m==13) sum++; } } } } } } } } } } } } } printf("%d/n",sum);}//法二:搜索#include <cstdio>#include <iostream>using namespace std;int count=0;void dfs(int step,int sum){//step為該走的步數,即該拿哪個號碼的牌了 sum為當前的牌總數 if(step==14){ count+=(sum==13); return; } if(sum>13) return; for(int i=0;i<=4;i++){ dfs(step+1,sum+i); }}int main(){ dfs(1,0); cout<<count<<endl; return 0;}8.移動距離 (15分)X星球居民小區的樓房全是一樣的,并且按矩陣樣式排列。其樓房的編號為1,2,3... 當排滿一行時,從下一行相鄰的樓往反方向排號。 比如:當小區排號寬度為6時,開始情形如下:
1 2 3 4 5 6
12 11 10 9 8 7
13 14 15 .....
我們的問題是:已知了兩個樓號m和n,需要求出它們之間的最短移動距離(不能斜線方向移動)
要求輸出一個整數,表示m n 兩樓間最短移動距離。
輸入格式:
在一行中輸入為3個整數w m n,空格分開,都在1到10000范圍內 w為排號寬度,m,n為待計算的樓號。
輸出格式:
要求輸出一個整數,表示m n 兩樓間最短移動距離。
輸入樣例1:
6 8 2輸出樣例1:
4輸入樣例2:
4 7 20輸出樣例2:
5//此題需要細致考慮各種情況//x:需要考慮此數(m和n)能不能除盡w//y:需要考慮此數(m和n)能不能除盡w,在此基礎上再考慮x在的行是正方向還是逆方向 #include <cstdio>#include <iostream>using namespace std;int main(){ int w,m,n; int x1,y1,x2,y2; cin>>w>>m>>n; x1=m/w+(m%w!=0); x2=n/w+(n%w!=0); y1=(m%w==0?(x1%2==0?1:w):(x1%2==0?w-m%w+1:m%w)); y2=(n%w==0?(x2%2==0?1:w):(x2%2==0?w-n%w+1:n%w)); cout<<(int)abs(x1-x2)+(int)abs(y1-y2)<<endl; return 0;}9.壘骰子 (25分)賭圣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 11 2輸出樣例:
544「數據范圍」
對于 30% 的數據:n <= 5對于 60% 的數據:n <= 100對于 100% 的數據:0 < n <= 10^9, m <= 36//首先想到的是搜索,但看到數據規模,最大已經達到了10^9,說明此題最佳方式不是搜索//于是考慮動態規劃://仔細一想,若設dp[i][j]為第i層頂面點數為j的方案數,則 Dp[i][j]就等于i-1高度時所有與j的反面無沖突的方案數累加//由這個狀態轉移方程從而看出了重疊子問題,最優子結構!!!說明可以用O(n)級別的動態規劃處理題目//而且對于大數據,肯定比搜索強,但能不能解決極端大數據未知//另外 后的總方案數還要乘以(4^n) 因為每一個骰子可以4面轉//由于 每一層的規劃只與前一層有關 所以可以采用滾動數組, 不然內存會超//代碼:#include <cstdio>#include <iostream>using namespace std;#define MOD 1000000007long long int quick_pow(int a,int n){ long long int temp=a,sum=1; while(n){ if(n&1) sum=(sum*temp)%MOD; temp=(temp*temp)%MOD; n=n>>1; } return sum;}int main(){ int n,m; int x,y; int conflict[7][7];//互斥面 為0表示互斥 int towards[7]={0,4,5,6,1,2,3};//骰子對稱面 long long int dp[2][7]; long long sum=0;//方案數 int e=0;//滾動標志 cin>>n>>m; for(int i=1;i<=6;i++){ for(int j=1;j<=6;j++){ conflict[i][j]=1; } } for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); conflict[x][y]=conflict[y][x]=0; } for(int i=1;i<=6;i++){//初始化第一層 先不考慮4面轉 dp[e][i]=1; } for(int i=2;i<=n;i++){//當前層 e=1-e; for(int j=1;j<=6;j++){//點數 dp[e][j]=0; for(int t=1;t<=6;t++){//找與當前點數的對面不沖突的點 if(conflict[towards[j]][t]){ dp[e][j]=(dp[e][j]+dp[1-e][t])%MOD; } } } } for(int i=1;i<=6;i++){ sum=(sum+dp[e][i])%MOD; } sum=(sum*quick_pow(4,n))%MOD;//四面轉 cout<<sum<<endl; return 0;}//以動態規劃的方式在O(N)的時間復雜度內求解, 但對于數據規模為10^9的數據而已, O(N)顯然是不夠的//以dp[i][j]來表示在高度為i的情況下, 骰子柱頂面點數為j的總方案數 //dp[i][j]的值將等于前一高度所有方案的選擇性累加//一說到選擇性累加,是不是可以聯想到矩陣相乘? //在用 矩陣快速冪的應用->優化遞推式 求斐波那契數列例子中//那個只包含0和1的矩陣就是這樣通過列向量的0或1對左邊矩陣進行選擇累加, 從而得出右邊矩陣的//那么, 我們也可以通過類似的結構來完成對骰子方案的選擇性累加//我們用一個單行矩陣dp[1][j]來記錄高度為N時, 頂面為j的總方案數//為了構造出利用矩陣相乘(矩陣dp X 矩陣conflict)進行選擇性疊加,對于conflict數組,進行一些改進://conflict[i][j]=0表示,i 與 j的對稱面 互斥#include <cstdio>#include <cstring>#include <iostream>using namespace std;#define MOD 1000000007struct matrix{//矩陣 long long int m[7][7];};long long int quick_pow(int a,int n){//快速冪 long long int c=1,temp=a; if(n==0) return 1; while(n){ if(n&1) c=(c*temp)%MOD; temp=(temp*temp)%MOD; n=n>>1; } return c;}void matrix_mul(long long int re[][7],long long int a[][7],long long int b[][7]){ for(int i=1;i<=6;i++){ if(a[0][i]){ for(int t=1;t<=6;t++){ re[0][t]=(re[0][t]+a[0][i]*b[i][t])%MOD; } } }}struct matrix mul(struct matrix a,struct matrix b){//定義的矩陣 相乘 struct matrix c; memset(c.m,0,sizeof(c.m)); for(int i=1;i<=6;i++){ for(int j=1;j<=6;j++){ if(a.m[i][j]){ for(int t=1;t<=6;t++){ c.m[i][t]=(c.m[i][t]+a.m[i][j]*b.m[j][t])%MOD; } } } } return c;}struct matrix quick_matrix_pow(struct matrix a,int n){//定義的矩陣 快速冪 struct matrix e,temp=a; memset(e.m,0,sizeof(e.m)); for(int i=1;i<=6;i++){ e.m[i][i]=1; } if(n==0) return e; while(n){ if(n&1) e=mul(e,temp); temp=mul(temp,temp); n=n>>1; } return e;}int main(){ int n,m,x,y; int towards[7]={0,4,5,6,1,2,3}; struct matrix mat,conflict;//把conflict表示為矩陣,便于相乘 long long int dp[1][7],result[1][7],sum=0;//這倆矩陣未表示為 定義的矩陣,直接用數組 cin>>n>>m; for(int i=1;i<=6;i++){ dp[0][i]=1; } for(int i=1;i<=6;i++){ for(int j=1;j<=6;j++){ conflict.m[i][j]=1; } } for(int i=1;i<=m;i++){ cin>>x>>y; conflict.m[x][towards[y]]=conflict.m[y][towards[x]]=0; } mat=quick_matrix_pow(conflict,n-1);//矩陣快速冪 memset(result,0,sizeof(result)); matrix_mul(result,dp,mat.m);//再用dp矩陣與mat.m矩陣相乘 放到result矩陣里 for(int i=1;i<=6;i++){ sum=(sum+result[0][i])%MOD; } sum=(sum*quick_pow(4,n))%MOD; cout<<sum<<endl; return 0;}10.生命之樹 (31分)在X森林里,上帝創建了生命之樹。
他給每棵樹的每個節點(葉子也稱為一個節點)上,都標了一個整數,代表這個點的和諧值。 上帝要在這棵樹內選出一個非空節點集S,使得對于S中的任意兩個點a,b,都存在一個點列 {a, v1, v2, ..., vk, b} 使得這個點列中的每個點都是S里面的元素,且序列中相鄰兩個點間有一條邊相連。
在這個前提下,上帝要使得S中的點所對應的整數的和盡量大。 這個最大的和就是上帝給生命之樹的評分。
經過atm的努力,他已經知道了上帝給每棵樹上每個節點上的整數。但是由于 atm 不擅長計算,他不知道怎樣有效的求評分。他需要你為他寫一個程序來計算一棵樹的分數。
輸入格式:
第一行一個整數 n 表示這棵樹有 n 個節點。 第二行 n 個整數,依次表示每個節點的評分。 接下來 n-1 行,每行 2 個整數 u, v,表示存在一條 u 到 v 的邊。由于這是一棵樹,所以是不存在環的。
輸出格式:
輸出一行一個數,表示上帝給這棵樹的分數。
輸入樣例:
51 -2 -3 4 54 23 11 22 5輸出樣例:
8數據范圍
對于 30% 的數據,n <= 10對于 100% 的數據,0 < n <= 10^5, 每個節點的評分的絕對值不超過 10^6 。//此題的樹其實為圖,此題結合了圖的深搜和dp:利用深度優先搜索遍歷圖,利用dp思想在遍歷過程解決問題//典型的樹狀dp,求權值最大的連通子圖//dp[i]表示:以i為根節點的子樹,權值之和中,最大的(因為是子樹,所以一定包含i節點)//dp[i] += dp[k],這里的k是指i的孩子節點,且dp[k]一定要是大于0的,如果小于0,會使總和變小,加它還不如不加//所以就用一個遞歸,從一個根節點出發,一直到葉子節點,//這時候就回溯了,回溯的時候就會把下層節點的dp值帶回到上層。每計算出一個i的dp值,//就與當前保存的最大值比較。#include <cstdio>#include <cstring>#include <iostream>using namespace std;//用前向星存圖struct edge{ int next; int to;}edges[100000];//從1開始存int head[100005];//從1開始存int weight[100005];//從1開始存int book[100005];int dp[100005];int cnt,n,max_weight=0;void Init(){//初始化 for(int i=1;i<=n;i++){ edges[i].next=0; edges[i].to=0; } for(int i=1;i<=n;i++){ head[i]=0; } cnt=0;}void Add(int x,int y){//加邊 cnt++; edges[cnt].next=head[x]; edges[cnt].to=y; head[x]=cnt;}void dfs(int x){//利用深度優先搜索遍歷圖 int y; for(int i=head[x];i;i=edges[i].next){ y=edges[i].to; if(!book[y]){ book[y]=1; dfs(y); dp[x]+=(dp[y]>0?dp[y]:0); } } if(dp[x]>max_weight) max_weight=dp[x];}int main(){ int x,y; cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&weight[i]); dp[i]=weight[i]; } for(int i=1;i<n;i++){ cin>>x>>y; Add(x,y); Add(y,x); } memset(book,0,sizeof(book)); book[1]=1; dfs(1); cout<<max_weight<<endl; return 0;}總結:15年省賽最后倆題都是動態規劃,備戰多看看dp
新聞熱點
疑難解答