蓝桥杯第4届预赛本科A组C语言真题解析.docx

上传人:b****6 文档编号:7081082 上传时间:2023-01-17 格式:DOCX 页数:25 大小:50.81KB
下载 相关 举报
蓝桥杯第4届预赛本科A组C语言真题解析.docx_第1页
第1页 / 共25页
蓝桥杯第4届预赛本科A组C语言真题解析.docx_第2页
第2页 / 共25页
蓝桥杯第4届预赛本科A组C语言真题解析.docx_第3页
第3页 / 共25页
蓝桥杯第4届预赛本科A组C语言真题解析.docx_第4页
第4页 / 共25页
蓝桥杯第4届预赛本科A组C语言真题解析.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

蓝桥杯第4届预赛本科A组C语言真题解析.docx

《蓝桥杯第4届预赛本科A组C语言真题解析.docx》由会员分享,可在线阅读,更多相关《蓝桥杯第4届预赛本科A组C语言真题解析.docx(25页珍藏版)》请在冰豆网上搜索。

蓝桥杯第4届预赛本科A组C语言真题解析.docx

蓝桥杯第4届预赛本科A组C语言真题解析

2013年蓝桥杯(第4届)预赛本科A组真题解析

高斯日记

大数学家高斯有个好习惯:

无论如何都要记日记。

他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:

4210

后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。

这或许也是个好习惯,它时时刻刻提醒着主人:

日子又过去一天,还有多少时光可以用于浪费呢?

高斯出生于:

1777年4月30日。

在高斯发现的一个重要定理的日记上标注着:

5343,因此可算出那天是:

1791年12月15日。

高斯获得博士学位的那天日记上标着:

8113

请你算出高斯获得博士学位的年月日。

提交答案的格式是:

yyyy-mm-dd,例如:

1980-03-21

(1)答案。

1799-07-16

(2)编程思路1。

从年的角度出发,先求出4月30日是1777年的第几天,加到日记标注的n上,并将n减1,这样n为从1777年1月1日开始的天数;再看n中有多少年(设为x),加到1777上,并从n中减去这x年包括的天数;最后求得剩余天数在1777+x年中的日期。

(3)源程序1。

#include

intisLeap(intyear);

intmain()

{

inta[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}};

intn;

scanf("%d",&n);

intyear=1777,month=4,day=30;//birth

for(inti=0;i<(month-1);i++)

{

n+=a[isLeap(year)][i];

}

n+=day-1;//此时n为从1777年1月1日开始天数

while(n>0)

{

if(isLeap(year))

n-=366;

else

n-=365;

year++;

}

if(n<0)

{

year--;

n=n+(isLeap(year)?

366:

365);

}

for(inti=0;n>0;i++)

{

day=n;

month=i;

n-=a[isLeap(year)][i];

}

printf("%d-%02d-%02d\n",year,month+1,day);

return0;

}

intisLeap(intyear)

{

if((year%4==0&&year%100!

=0)||(year%400==0))

return1;

else

return0;

}

(4)编程思路2。

从月的角度出发,先将输入的日志标记天数n加30减2,表示从4月1日开始算;再从1777年4月开始,逐月从n中减去各月的天数,同时修改对应年份和月份,直到剩余的n不足1个月的天数,就可以求得结果。

(5)源程序2。

#include

intisLeap(intyear);

intmain()

{

inta[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}};

intn;

scanf("%d",&n);

intyear=1777,month=4,day=30;//birth

n=n+day-2;day=1;

while(n>=a[isLeap(year)][month-1])

{

n-=a[isLeap(year)][month-1];

month++;

if(month>12)

{year++;month=1;}

}

printf("%d-%02d-%02d\n",year,month,day+n);

return0;

}

intisLeap(intyear)

{

if((year%4==0&&year%100!

=0)||(year%400==0))

return1;

else

return0;

}

排它平方数

小明正看着203879这个数字发呆。

原来,203879*203879=41566646641

这有什么神奇呢?

仔细观察,203879是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。

具有这样特点的6位数还有一个,请你找出它!

(1)正确答案。

639172

(2)编程思路。

对6位数进行穷举,区间下限为123456,上限为987654。

定义数组used[10]记录数字0~9的使用情况,分离出穷举的6位数的各位x,且置used[x]++,若每个used[x]大于2,则数字x重复出现,不合要求,进行下次穷举。

另外,由于两个6位数相乘结果超出了整型数的表示范围,采用两个数组元素来保存积。

计算6位数i的平方时,将i表示为a*10000+b,这样i的平方等于a*a*100000000+2*a*b*10000+b*b,用数组元素x[1]保存低8位,用x[0]保存高8位,具体方法为:

x[1]=x[1]+c%10000*10000;

x[0]=x[0]+c/10000;

x[0]=x[0]+x[1]/100000000;

x[1]=x[1]%100000000;

然后再检测x[0]和x[1]中的各位数k是否已出现,即对应的used[k]是否为1。

(3)源程序。

#include

intcheck(intx,intused[10])

{

do{

if(used[x%10]>0)

return0;

else

used[x%10]++;

}while(x/=10);

return1;

}

intcheckpower(intx[],intused[10])

{

do{

if(used[x[0]%10]>0){

return0;

}

}while(x[0]/=10);

for(inti=1;i<=8;i++)

{

if(used[x[1]%10]>0)

return0;

x[1]=x[1]/10;

}

return1;

}

intmain()

{

inti,a,b,c,x[2];

intk,used[10];

for(i=123456;i<=987654;i++)

{

for(k=0;k<=9;k++)

used[k]=0;

if(!

check(i,used))

continue;

a=i/10000;b=i%10000;

x[0]=a*a;x[1]=b*b;

c=2*a*b;

x[1]=x[1]+c%10000*10000;

x[0]=x[0]+c/10000;

x[0]=x[0]+x[1]/100000000;

x[1]=x[1]%100000000;

if(!

checkpower(x,used))

continue;

printf("%d\n",i);

}

return0;

}

振兴中华

小明参加了学校的趣味运动会,其中的一个项目是:

跳格子。

地上画着一些格子,每个格子里写一个字,如下所示:

比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。

一直要跳到“华”字结束。

要求跳过的路线刚好构成“从我做起振兴中华”这句话。

请你帮助小明算一算他一共有多少种可能的跳跃路线呢?

(1)答案。

35

(2)编程思路。

图中有4行5列共20个格子,定义数组inta[4][5],其中元素a[i][j]保存走到第i行第j列的格子的方法数。

由于要求跳过的路线刚好构成“从我做起振兴中华”这句话,因此每个格子只能由其正上方或最左边的格子走过来,因此有:

a[i][j]=a[i-1][j]+a[i][j-1];(1≤i≤3,1≤j≤4)

初始时,a[0][j]=1;(0≤i≤3)

a[0][j]=1;(0≤j≤4)

(3)源程序。

#include

intmain()

{

inti,j;

inta[4][5]={0};

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

a[i][0]=1;

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

a[0][j]=1;

for(i=1;i<4;i++)

for(j=1;j<5;j++)

a[i][j]=a[i-1][j]+a[i][j-1];

printf("%d\n",a[3][4]);

return0;

}

颠倒的价牌

小李的店里专卖其它店中下架的样品电视机,可称为:

样品电视专卖店。

其标价都是4位数字(即千元不等)。

小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参见p1.jpg)。

这种价牌有个特点,对一些数字,倒过来看也是合理的数字。

如:

1256890都可以。

这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,比如:

1958倒着挂就是:

8561,差了几千元啊!

!

当然,多数情况不能倒读,比如,1110就不能倒过来,因为0不能作为开始数字。

有一天,悲剧终于发生了。

某个店员不小心把店里的某两个价格牌给挂倒了。

并且这两个价格牌的电视机都卖出去了!

庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。

请根据这些信息计算:

赔钱的那个价牌正确的价格应该是多少?

(1)答案。

9088

(2)编程思路。

在0~9这10个数字中,只有0,1,2,5,6,8,9这7个数字(保存到数组num1中)颠倒后有意义,它们颠倒后对应数字为0,1,2,5,9,8,6(保存到数组num2中)。

设a、b、c、d分别表示价牌上4位数字的千位、百位、十位和个位,显然a、d位上的数字不能取0。

对a(1~6)、b(0~6)、c(0~6)、d(1~6)的组合情况进行穷举,找出这些组合情况中价差在-300~-200(亏2百多)的数字保存到数组price1中,价差在800~900(赚8百多)的数字保存到数组price2中。

最后对数组price1和price2中的元素进行两两匹配,找到价差之和等于558的情况。

(3)源程序。

#include

intmain()

{

intnum1[7]={0,1,2,5,6,8,9},num2[7]={0,1,2,5,9,8,6};

intprice1[1000][2],price2[1000][2];

inta,b,c,d,cnt1=0,cnt2=0;

for(a=1;a<=6;a++)

for(b=0;b<=6;b++)

for(c=0;c<=6;c++)

for(d=1;d<=6;d++)

{

inttemp1=num1[a]*1000+num1[b]*100+num1[c]*10+num1[d];

inttemp2=num2[d]*1000+num2[c]*100+num2[b]*10+num2[a];

if(temp2-temp1>-300&&temp2-temp1<-200)

{

price1[cnt1][0]=temp1;

price1[cnt1][1]=temp2-temp1;

cnt1++;

}

elseif(temp2-temp1>800&&temp2-temp1<900)

{

price2[cnt2][0]=temp1;

price2[cnt2][1]=temp2-temp1;

cnt2++;

}

}

for(a=0;a

for(b=0;b

{

if(price1[a][1]+price2[b][1]==558)

printf("%d,%d\n",price1[a][0],price2[b][0]);

}

return0;

}

前缀判断

如下的代码判断needle_start指向的串是否为haystack_start指向的串的前缀,如不是,则返回NULL。

比如:

"abcd1234"就包含了"abc"为前缀

char*prefix(char*haystack_start,char*needle_start)

{

char*haystack=haystack_start;

char*needle=needle_start;

while(*haystack&&*needle){

if(______________________________)returnNULL;//填空位置

}

if(*needle)returnNULL;

returnhaystack_start;

}

(1)参考答案。

*(haystack++)!

=*(needle++)

逆波兰表达式

正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的,机器求解并不方便。

例如:

3+5*(2+6)-1

而且,常常需要用括号来改变运算次序。

相反,如果使用逆波兰表达式(前缀表达式)表示,上面的算式则表示为:

-+3*5+261

不再需要括号,机器可以用递归的方法很方便地求解。

为了简便,我们假设:

1.只有+-*三种运算符

2.每个运算数都是一个小于10的非负整数

下面的程序对一个逆波兰表示串进行求值。

其返回值为一个结构:

其中第一元素表示求值结果,第二个元素表示它已解析的字符数。

structEV

{

intresult;//计算结果

intn;//消耗掉的字符数

};

structEVevaluate(char*x)

{

structEVev={0,0};

structEVv1;

structEVv2;

if(*x==0)returnev;

if(x[0]>='0'&&x[0]<='9'){

ev.result=x[0]-'0';

ev.n=1;

returnev;

}

v1=evaluate(x+1);

v2=_____________________________;//填空位置

if(x[0]=='+')ev.result=v1.result+v2.result;

if(x[0]=='*')ev.result=v1.result*v2.result;

if(x[0]=='-')ev.result=v1.result-v2.result;

ev.n=1+v1.n+v2.n;

returnev;

}

(1)参考答案。

evaluate(x+1+v1.n)

错误票据

某涉密单位下发了某种票据,并要在年终全部收回。

每张票据有唯一的ID号。

全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。

因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。

你的任务是通过编程,找出断号的ID和重号的ID。

假设断号不可能发生在最大和最小号。

要求程序首先输入一个整数N(N<100)表示后面数据行数。

接着读入N行数据。

每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000),请注意行内和行末可能有多余的空格,你的程序需要能处理这些空格。

每个整数代表一个ID号。

要求程序输出1行,含两个整数mn,用空格分隔。

其中,m表示断号ID,n表示重号ID

例如:

用户输入:

2

568119

10129

则程序输出:

79

再例如:

用户输入:

6

164178108109180155141159104182179118137184115124125129168196

172189127107112192103131133169158

128102110148139157140195197

185152135106123173122136174191145116151143175120161134162190

149138142146199126165156153193144166170121171132101194187188

113130176154177120117150114183186181100163160167147198111119

则程序输出:

105120

(1)编程思路。

因为作为ID号的正整数不大于100000,因此可以定义一个数组inthash[100001],其中hash[i]的值表示正整数i出现的次数,初始时元素值全为0。

在读入数据的过程中,每读入一个数num,使hash[num]元素值加1。

同时记录下所读入数据的最小值min和最大值max。

由于断号不可能发生在最大和最小号,因此,数据读入完成后,扫描下标为min~max之间的hash数组元素,数组元素值为0所对应的下标是所求的断号m,重号n即是数组元素值为2所对应的下标。

另外,本题的输入行数是确定的,但每行中数据个数不确定,因此采用字符串来读取每行,然后以空格为分界点进行读取各个数字。

需要注意的是:

题目特意强调行内和行末可能有多余的空格,程序需要能处理这些空格。

(2)源程序。

#include

#include

inthash[100001]={0};

charmess[1000000];

intmain()

{

intN;

scanf("%d",&N);

getchar();

intmax=0,min=100001;

while(N--)

{

gets(mess);

intnum=0;

for(inti=0;mess[i]!

='\0';i++)

{

if(mess[i]!

='')//读入数字进行数值的转换

{

num=num*10+mess[i]-'0';

}

else

{

if(num==0)continue;//前面一定是多余的空格

hash[num]++;

if(min>num)min=num;

if(max

num=0;

}

}

if(num!

=0)//每行最后一个数,但行尾无空格

{

hash[num]++;

if(min>num)min=num;

if(max

}

}

intm=0,n=0;

for(inti=min;i<=max;i++)

{

if(hash[i]==0)m=i;

if(hash[i]==2)n=i;

if(m!

=0&&n!

=0)break;

}

printf("%d%d\n",m,n);

return0;

}

买不到的数目

小明开了一家糖果店。

他别出心裁:

把水果糖包成4颗一包和7颗一包的两种。

糖果不能拆包卖。

小朋友来买糖的时候,他就用这两种包装来组合。

当然有些糖果数目是无法组合出来的,比如要买10颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。

大于17的任何数字都可以用4和7组合出来。

本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入:

两个正整数,表示每种包装中糖的颗数(都不多于1000)

要求输出:

一个正整数,表示最大不能买到的糖数

不需要考虑无解的情况

例如:

用户输入:

47

程序应该输出:

17

再例如:

用户输入:

35

程序应该输出:

7

(1)编程思路。

采用穷举法完成。

设输入的两个正整数分别为a和b,且设两数的最小公倍数为G。

进行糖果组合时,两种糖果的数目分别取i和j,则糖果的组合算式为a*i+b*j。

对糖果数目i和j进行穷举,穷举的下界均为0,上界分别为G/b、G/a。

定义数组intvis[1000001]={0};,初始值全为0。

穷举每种包装的数目时,若a*i+b*j小于G,则置vis[a*i+b*j]=1。

穷举完成后,数组vis中元素值为0的元素vis[k]表示数量为k的糖果数买不到。

(2)源程序。

#include

intvis[1000001]={0};

intgcd(intm,intn)

{

intr=m%n;

while(r!

=0)

{

m=n;n=r;r=m%n;

}

returnn;

}

intmain()

{

inta,b;

scanf("%d%d",&a,&b);

intmaxn=a*b/gcd(a,b);

for(inti=0;i*a<=maxn;i++)

{

for(intj=0;j*b<=maxn;j++)

{

if(i*a+j*b>maxn)break;

vis[i*a+j*b]=1;

}

}

for(inti=maxn;i>0;i--)

{

if(vis[i]==0)

{

printf("%d\n",i);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 幼儿读物

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1