1. 程式人生 > >藍橋杯 2011年省賽(1-10題)

藍橋杯 2011年省賽(1-10題)

1. 程式碼填空 (滿分3分)

神祕的三位數

有這樣一個3位數,組成它的3個數字階乘之和正好等於它本身。即:abc = a! + b! + c!

下面的程式用於搜尋這樣的3位數。請補全缺失的程式碼。

int JC[] = {1,1,2,6,24,120,720,5040,40320,362880};

int i;

for(i=100; i<1000; i++)

{

int sum = 0;

int x = i;

while(____)

{

sum += JC[x%10];

x /= 10;

}

if(i==sum) printf("%d\n", i);

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
int c[]={1,1,2,6,24,120,720,5040,40320,362880};
int main()
{
	int i;
	for(i=100;i<=1000;i++)
	{
		int sum=0;
		int x=i;
		while(x)
		{
			sum+=c[x%10];
			x/=10;
		}
		if(i==sum)
			printf("%d\n",i);
	}
	return 0;
}

2. 程式碼填空 (滿分4分)

歌賽新規則

歌手大賽的評分規則一般是去掉一個最高分,去掉一個最低分,剩下的分數求平均。當評委較少的時候,如果我們只允許去掉一個分數,該如何設計規則呢?

有人提出:應該去掉與其餘的分數平均值相差最遠的那個分數。即“最離群”的分數。

以下的程式用於實現這個功能。其中x存放所有評分,n表示陣列中元素的個數。函式返回最“離群”的那個分數值。請補全缺失的程式碼。

double score(double x[], int n)

{

int i,j;

double dif = -1;

double bad;

for(i=0; i<n; i++)

{

double sum = 0;

for(j=0; j<n; j++)

{

if(________) sum += x[j];

}

double t = x[i] - sum / (n-1);

if(t<0) t = -t;

if(t>dif)

{

dif = t;

bad = x[i];

printf("%d, %f\n", i, x[i]);

}

}

return bad;

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
double a[N];
double score(double *x,int n)
{
	int i,j;
	double dif=-1;
	double bad;
	for(i=0;i<n;i++)
	{
		double sum=0;
		for(j=0;j<n;j++)
		{
			if(j!=i)
				sum+=x[j];
		}
		double t=x[i]-sum/(n-1);
		if(t<0)
			t=-t;
		if(t>dif)
		{
			dif=t;
			bad=x[i];
			printf("%d, %lf\n",i,x[i]);
		}
	}
	return bad;
}
int main()
{
	int n,i;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=0;i<n;i++)
			scanf("%lf",&a[i]);
		printf("%lf\n",score(a,n));
	}
	return 0;
}

3. 程式碼填空 (滿分4分)

反轉串

我們把“cba”稱為“abc”的反轉串。

下面的程式碼可以把buf中的字元反轉。其中n表示buf中待反轉的串的長度。請補充缺少的程式碼。

void reverse_str(char* buf, int n)

{

if(n<2) return;

char tmp = buf[0];

buf[0] = buf[n-1];

buf[n-1] = tmp;

_______________________________;

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
char s[N];
void reverse_str(char *buf,int n)
{
	if(n<2)
		return ;
	char tmp=buf[0];
	buf[0]=buf[n-1];
	buf[n-1]=tmp;
	reverse_str(buf+1,n-2);
}
int main()
{
	int l;
	while(scanf("%s",s)!=EOF)
	{
		l=strlen(s);
		reverse_str(s,l);
		printf("%s\n",s);
	}
	return 0;
}

4. 程式碼填空 (滿分5分)

n進位制小數

將任意十進位制正小數分別轉換成2,3,4,5,6,7,8,9進位制正小數,小數點後保留8位,並輸出。例如:若十進位制小數為0.795,則輸出:

十進位制正小數 0.795000 轉換成 進位制數為: 0.11001011

十進位制正小數 0.795000 轉換成 進位制數為: 0.21011011

十進位制正小數 0.795000 轉換成 進位制數為: 0.30232011

十進位制正小數 0.795000 轉換成 進位制數為: 0.34414141

十進位制正小數 0.795000 轉換成 進位制數為: 0.44341530

十進位制正小數 0.795000 轉換成 進位制數為: 0.53645364

十進位制正小數 0.795000 轉換成 進位制數為: 0.62702436

十進位制正小數 0.795000 轉換成 進位制數為: 0.71348853

以下程式碼提供了這個功能。其中,dTestNo表示待轉的十進位制小數。iBase表示進位制數。請填寫缺失的部分。

void fun(double dTestNo, int iBase)

{

int iT[8];

int iNo;

printf("十進位制正小數 %f 轉換成 %d 進位制數為: ",dTestNo, iBase);

for(iNo=0;iNo<8;iNo++)

{

dTestNo *= iBase;

iT[iNo] = ________________;

if(___________________) dTestNo -= iT[iNo];

}

printf("0.");

for(iNo=0; iNo<8; iNo++) printf("%d", iT[iNo]);

printf("\n");

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
void fun(double dTestNo, int iBase)
{
	int iT[8];
	int iNo;
	printf("十進位制正小數 %f 轉換成 %d 進位制數為: ",dTestNo, iBase);
	for(iNo=0;iNo<8;iNo++)
	{
		dTestNo *= iBase;
		iT[iNo] = (int)dTestNo;
		if(iT[iNo]) 
			dTestNo -= iT[iNo];
	}
	printf("0.");
	for(iNo=0; iNo<8; iNo++)
	    printf("%d", iT[iNo]);
	printf("\n");
}
int main()
{
	double n;
	while(scanf("%lf",&n)!=EOF)
	{
		for(int i=2;i<10;i++)
			fun(n,i);
	}
	return 0;
}

5. 程式碼填空 (滿分6分)

輪換

串“abcd”每個字元都向右移位,最右的移動到第一個字元的位置,就變為“dabc”。這稱為對串進行位移=1的輪換。同理,“abcd”變為:“cdab”則稱為位移=2的輪換。

下面的程式碼實現了對串s進行位移為n的輪換。請補全缺失的程式碼。

void shift(char* s, int n)

{

char* p;

char* q;

int len = strlen(s);

if(len==0) return;

if(n<=0 || n>=len) return;

char* s2 = (char*)malloc(_________);

p = s;

q = s2 + n % len;

while(*p)

{

*q++ = *p++;

if(q-s2>=len)

{

*q = ___________;

q = s2;

}

}

strcpy(s,s2);

free(s2);

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
char s[N];
void shift(char* s, int n)
{
	char* p;
	char* q;
	int len = strlen(s);
	if(len==0) 
		return;
	if(n<=0 || n>=len) 
		return;
	char* s2 = (char*)malloc(sizeof(char)*(len+1));//
	p = s;
	q = s2 + n % len;
	while(*p)
	{
		*q++ = *p++;
		if(q-s2>=len)
		{
			*q = '\0';//
			q = s2;
		}
	}
	strcpy(s,s2);
	free(s2);
}
int main()
{
	int n;
	while(scanf("%s%d",s,&n)!=EOF)
	{
		shift(s,n);
		printf("%s\n",s);
	}
	return 0;
}

6. 程式碼填空 (滿分9分)

中獎計算

某抽獎活動的規則是:每位參與者在紙上寫下一個8位數的號碼。最後通過搖獎的辦法隨機產生一個8位數字。參與者寫下的數字中最多有多少個連續位與開獎號碼中的相同,則稱為中了幾個號。

例如:小張寫的數字是:12345678,而開獎號碼是:42347856。則稱小張中了3個號,因為其中最長的相同連續位是:“234”。如果小張寫的是:87654321,則他只中了一個號。

下面的程式碼根據傳入的引數,返回中了幾個號。其中:a表示被評價的號碼,b表示搖號產生的數字。請填寫缺少的程式碼。

int g(int a, int b)

{

char sa[]="00000000";

char sb[]="00000000";

int n = 0;

int i,j;

sprintf(sa,"%8d",a);

sprintf(sb,"%8d",b);

for(i=0; i<8; i++)

{

for(j=1; j<=8-i; j++)

{

char t = ________;

sa[i+j] = 0;

if(strstr(sb, sa+i))

{

if(j>n) _________;

}

sa[i+j] = t;

}

}

return n;

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
int g(int a, int b)
{
	char sa[]="00000000";
	char sb[]="00000000";
	int n = 0;
	int i,j;
	sprintf(sa,"%8d",a);
	sprintf(sb,"%8d",b);
	for(i=0; i<8; i++)
	{
		for(j=1; j<=8-i; j++)
		{
			char t = sa[i+j];
			sa[i+j] = 0;
			if(strstr(sb, sa+i))
			{
				if(j>n) n=j;
			}
			sa[i+j] = t;
		}
	}
	return n;
}
int main()
{
	int a,b;
	while(scanf("%d%d",&a,&b)!=EOF)
	{
		printf("%d\n",g(a,b));
	}
	return 0;
}


7. 程式碼填空 (滿分10分)

概率問題

某個袋子中有紅球m個,白球n個。現在要從中取出x個球。那麼紅球數目多於白球的概率是多少呢?

下面的程式碼解決了這個問題。其中的y表示紅球至少出現的次數。

這與前文的問題是等價的。因為如果取30個球,要求紅球數大於白球數,則等價於至少取出16個紅球。請根據僅存的線索,判斷程式邏輯,並補全缺少的程式碼。

/*

m: 袋中紅球的數目

n: 袋中白球的數目

x: 需要取出的數目

y: 紅球至少出現的次數

*/

double pro(int m, int n, int x, int y)

{

if(y>x) return 0;

if(y==0) return 1;

if(y>m) return 0;

if(x-n>y) return 1;

double p1 = _______________________;

double p2 = _______________________;

return (double)m/(m+n) * p1 + (double)n/(m+n) * p2;

}

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
using namespace std;
double pro(int m, int n, int x, int y)
{
	if(y>x) return 0;
	if(y==0) return 1;
	if(y>m) return 0;
	if(x-n>y) return 1;
	double p1 = pro(m-1,n,x-1,y-1);//取紅球 
	double p2 = pro(m,n-1,x-1,y);//取白球 
	return (double)m/(m+n) * p1 + (double)n/(m+n) * p2;
}
int main()
{
	int n,m,x,y;
	while(scanf("%d%d%d",&m,&n,&x)!=EOF)
	{
		y=(x/2)+1;
		printf("%lf\n",pro(m,n,x,y));
	}
	return 0;
} 

8. 程式設計(滿分15分)

方陣的主對角線之上稱為“上三角”。

請你設計一個用於填充n階方陣的上三角區域的程式。填充的規則是:使用1,2,3….的自然數列,從左上角開始,按照順時針方向螺旋填充。

例如:當n=3時,輸出:

1 2 3

6 4

5

當n=4時,輸出:

1 2 3 4

9 10 5

8 6

7

當n=5時,輸出:

1 2 3 4 5

12 13 14 6

11 15 7

10 8

9

程式執行時,要求使用者輸入整數n(3~20)

程式輸出:方陣的上三角部分。

要求格式:每個資料寬度為4,右對齊。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 50
using namespace std;
int a[N][N];
int main()
{
	int n,i,j,k;
	while(scanf("%d",&n)!=EOF)
	{
		int sum=0;
		for(i=1;i<=n;i++)
			sum+=i;
		memset(a,0,sizeof(a));
		a[0][0]=k=1;
		i=j=0;
		while(k<sum)
		{		
			while(j+1<n&&!a[i][j+1])
				a[i][++j]=++k;
			while(i+1<n&&!a[i+1][j-1])
				a[++i][--j]=++k;
			while(i-1>=0&&!a[i-1][j])
				a[--i][j]=++k;
		}
		for(i=0;i<n;i++)
		{
			for(j=0;j<n-i;j++)
			{
				printf("%4d",a[i][j]);
			}
			printf("\n");
		}
	}
	return 0;
	
}

9. 程式設計(滿分16分)

公司發了某商店的購物券1000元,限定只能購買店中的m種商品。每種商品的價格分別為m1,m2,…,要求程式列出所有的正好能消費完該購物券的不同購物方法。

程式輸入:

第一行是一個整數m,代表可購買的商品的種類數。

接下來是m個整數,每個1行,分別代表這m種商品的單價。

程式輸出:

第一行是一個整數,表示共有多少種方案

第二行開始,每種方案佔1行,表示對每種商品購買的數量,中間用空格分隔。

例如:

輸入:

2

200

300

則應輸出:

2

2 2

5 0

輸入:

2

500

800

則應輸出:

1

2 0

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define N 1010
int k;
int gm;//商品種類數 
int p[N];//單價 
int c[N];//商品個數 
int dp[N][N];//dp[i][j]表示第i種方法第j件商品的個數 
int sum;//當前花費 
void dfs(int m)
{
	int i;
	if(sum==1000)
	{
		for(i=0;i<gm;i++)
			dp[k][i]=c[i];
		k++;
		return ;
	}
	if(sum>1000||m<0)
		return ;
	c[m]++;
	sum+=p[m];
	dfs(m);
	c[m]--;
	sum-=p[m];
	dfs(m-1);
}
int main()
{
	int m,i,j;
	while(scanf("%d",&m)!=EOF)
	{
		gm=m;
		for(i=0;i<m;i++)
			scanf("%d",&p[i]);
		dfs(m-1);
		printf("%d\n",k);
		for(i=0;i<k;i++)
		{
			for(j=0;j<gm;j++)
			{
				printf(j?" %d":"%d",dp[i][j]);
			}
			printf("\n");
		}
	}
	return 0;
}

10. 程式設計(滿分28分)

一種Playfair密碼變種加密方法如下:首先選擇一個金鑰單詞(稱為pair)(字母不重複,且都為小寫字母),然後與字母表中其他字母一起填入至一個5x5方陣中,填入方法如下:

1.首先按行填入金鑰串。

2.緊接其後,按字母序按行填入不在金鑰串中的字母。

3.由於方陣中只有25個位置,最後剩下的那個字母則不需變換。

如果金鑰為youandme,則該方陣如下: 

y o u a n

d m e b c

f g h i j

k l p q r

s t v w x

在加密一對字母時,如am,在方陣中找到以這兩個字母為頂點的矩形(紅色字型):

y o u a n

d m e b c

f g h i j

k l p q r

s t v w x

這對字母的加密字母為該矩形的另一對頂點,如本例中為ob

請設計程式,使用上述方法對輸入串進行加密,並輸出加密後的串。

另外有如下規定:

1一對一對取字母,如果最後只剩下一個字母,則不變換,直接放入加密串中;

2、如果一對字母中的兩個字母相同,則不變換,直接放入加密串中;

3、如果一對字母中有一個字母不在正方形中,則不變換,直接放入加密串中;

4、如果字母對出現在方陣中的同一行或同一列,如dfhi,則只需簡單對調這兩個字母,即變換為fdih

5、如果在正方形中能夠找到以字母對為頂點的矩形,假如字母對為am,則該矩形的另一對頂點字母中,與a同行的字母應在前面,在上例中應是ob;同樣若待變換的字母對為ta,則變換後的字母對應為wo

6、本程式中輸入串均為小寫字母,並不含標點、空格或其它字元。

解密方法與加密相同,即對加密後的字串再加密,將得到原始串。

要求輸入形式如下:

從控制檯輸入兩行字串,第一行為金鑰單詞(長度小於等於25),第二行為待加密字串(長度小於等於50),兩行字串末尾都有一個回車換行符,並且兩行字串均為小寫字母,不含其它字元。

在標準輸出上輸出加密後的字串。

例如,若輸入:

youandme

welcometohangzhou

則表示輸入的金鑰單詞為youandme,形成的正方形如上所示;待加密字串為welcometohangzhou。在正方形中可以找到以第一對字母we為頂點的矩形,對應另一對頂點字母為vb,因此加密後為vb,同理可找到與字母對lc,et,oh,ho對應的頂點字母對。而字母對om位於上述正方形中的同一列,所以直接以顛倒這兩個字母來加密,即為mo,字母對an同理。字母對gz中的z不在上述正方形中,因此原樣放到加密串中。最後剩一個字母u也原樣輸出。

因此輸出的結果為:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct zz
{
	int x;
	int y;
}p[30];
int vis[30];
char s[30];
char ss[60];
char s1[60];
char map[6][6];
int main()
{
	int i,j;
	while(scanf("%s%s",s,ss)!=EOF)
	{
		memset(vis,0,sizeof(vis));
		int l=strlen(s);
		int ls=strlen(ss);
		for(i=0;i<l;i++)
		{
			p[s[i]-'a'].x=i/5;
			p[s[i]-'a'].y=i%5;
			map[i/5][i%5]=s[i];
			vis[s[i]-'a']=1;
		}
		for(i=l;i<25;i++)
		{
			int flag=0;
			for(j=0;j<26;j++)
			{	
				if(!vis[j])
				{
					p[j].x=i/5;
					p[j].y=i%5;
					map[i/5][i%5]='a'+j;
					flag=1;
					vis[j]=1;
				}
				if(flag)
					break;
			}
		}
//		for(i=0;i<5;i++)
//		{
//			for(j=0;j<5;j++)
//			{
//				printf("%c",map[i][j]);
//			}
//			printf("\n");
//		}
		int k=0;
		for(i=0;i<ls;i+=2)
		{
			int x1=ss[i]-'a';
			int x2=ss[i+1]-'a';
			if(vis[x1]&&vis[x2]&&p[x1].x!=p[x2].x&&p[x1].y!=p[x2].y)
			{
				s1[k++]=map[p[x1].x][p[x2].y];
				s1[k++]=map[p[x2].x][p[x1].y];
			}
			else if(vis[x1]&&vis[x2]&&(p[x1].x==p[x2].x||p[x1].y==p[x2].y))
			{
				s1[k++]=map[p[x2].x][p[x2].y];
				s1[k++]=map[p[x1].x][p[x1].y];
			}
			else if(!vis[x1]||!vis[x2])
			{
				s1[k++]=ss[i];
				s1[k++]=ss[i+1];
			}
			else if(ls&1)
				s1[k++]=ss[ls-1];
		}
		printf("%s\n",s1);
	}
	return 0;
}