蓝桥杯第5届预赛高职高专组C语言真题解析.docx
《蓝桥杯第5届预赛高职高专组C语言真题解析.docx》由会员分享,可在线阅读,更多相关《蓝桥杯第5届预赛高职高专组C语言真题解析.docx(25页珍藏版)》请在冰豆网上搜索。
蓝桥杯第5届预赛高职高专组C语言真题解析
2014年蓝桥杯(第5届)预赛高职高专组真题解析
武功秘籍
小明到X山洞探险,捡到一本有破损的武功秘籍(2000多页!
当然是伪造的)。
他注意到:
书的第10页和第11页在同一张纸上,但第11页和第12页不在同一张纸上。
小明只想练习该书的第81页到第92页的武功,又不想带着整本书。
请问他至少要撕下多少张纸带走?
这是个整数,请通过浏览器提交该数字,不要填写任何多余的内容。
(1)答案。
7
(2)编程思路。
因为每页页码开始为偶数,终止为奇数,因此若开始页码为奇数或终止页码为偶数,则应多加1页。
(3)源程序。
#include
intmain()
{
intm,n,ans;
while(scanf("%d%d",&n,&m)!
=EOF)
{
ans=m-n+2;
ans/=2;
if(n%2!
=0&&m%2==0)
ans++;
printf("%d\n",ans);
}
return0;
}
等额本金
小明从银行贷款3万元。
约定分24个月,以等额本金方式还款。
这种还款方式就是把贷款额度等分到24个月。
每个月除了要还固定的本金外,还要还贷款余额在一个月中产生的利息。
假设月利率是:
0.005,即:
千分之五。
那么,
第一个月,小明要还本金1250,还要还利息:
30000*0.005,总计1400.00
第二个月,本金仍然要还1250,但利息为:
(30000-1250)*0.005总计1393.75
请问:
小明在第15个月,应该还款多少(本金和利息的总和)?
请把答案金额四舍五入后,保留两位小数。
注意:
32.5,一定要写为:
32.50
通过浏览器提交答案,这是一个含有小数点和两位小数的浮点数字。
不要写多余内容(例如:
多写了“元”或添加说明文字)
(1)答案。
1312.50
(2)编程思路。
简单循环计算。
(3)源程序。
#include
intmain()
{
doublen=30000;
intm=24;
for(inti=1;i<=m;i++)
{
printf("%d%.2f\n",i,1250+n*0.005);
n-=1250;
}
return0;
}
猜字母
把abcd...s共19个字母组成的序列重复拼接106次,得到长度为2014的串。
接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母。
得到的新串再进行删除奇数位置字母的动作。
如此下去,最后只剩下一个字母,请写出该字母。
答案是一个小写字母,请通过浏览器提交答案。
不要填写任何多余的内容。
(1)答案。
q
(2)编程思路。
用循环直接模拟删除字符的过程。
(3)源程序。
#include
intmain()
{
charstr[2015];
charsrc[20]="abcdefghijklmnopqrs";
intn,i,k;
for(n=1,k=0;n<=106;n++)
{
for(i=0;i<19;i++)
str[k++]=src[i];
}
str[k]=0;
intlen=k;
while(len>1)
{
for(k=0,i=0;str[i]!
='\0';i++)
if(i%2!
=0)str[k++]=str[i];
str[k]='\0';
len=k;
}
printf("%s\n",str);
return0;
}
大衍数列
中国古代文献中,曾记载过“大衍数列”,主要用于解释中国传统文化中的太极衍生原理。
它的前几项是:
0、2、4、8、12、18、24、32、40、50...
其规律是:
对偶数项,是序号平方再除2,奇数项,是序号平方减1再除2。
以下的代码打印出了大衍数列的前100项。
intmain()
{
inti;
for(i=1;i<100;i++){
if(__________________)//填空
printf("%d",i*i/2);
else
printf("%d",(i*i-1)/2);
}
printf("\n");
}
请填写划线部分缺失的代码。
通过浏览器提交答案。
注意:
不要填写题面已有的内容,也不要填写任何说明、解释文字。
(1)参考答案。
i%2==0
打印图形
小明在X星球的城堡中发现了如下图形和文字:
小明开动脑筋,编写了如下的程序,实现该图形的打印。
#defineN70
voidf(chara[][N],intrank,introw,intcol)
{
if(rank==1){
a[row][col]='*';
return;
}
intw=1;
inti;
for(i=0;i____________________________________________;
f(a,rank-1,row+w/2,col);
f(a,rank-1,row+w/2,col+w);
}
intmain()
{
chara[N][N];
inti,j;
for(i=0;ifor(j=0;jf(a,6,0,0);
for(i=0;ifor(j=0;jprintf("\n");
}
return0;
}
请仔细分析程序逻辑,填写缺失代码部分。
(1)参考答案。
f(a,rank-1,row,col+w/2);
神奇算式
由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
210x6=1260
8x473=3784
27x81=2187
都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。
请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:
列出所有算式)。
(1)正确答案。
12
(2)编程思路。
采用穷举法来解决。
穷举对象分别为积和那个较小的乘数。
其中积是一个4位数,取值范围为1023~9876,乘数的取值范围为2~98。
循环体中需要检测两个约束条件:
1)积这个4位数中每一位数字不允许重复;2)这4个数字出现且仅出现2次。
这些约束条件可使用一个标记数组used[10]来处理。
used数组的初值全为0,当数字i使用后,置used[i]=1,若数字i再次使用时,此时used[i]又等于1,则可判定约束条件不满足。
(3)源程序。
#include
intcheck(intx,inty,intused[10])
{
inti,tmp[10]={0};
do{
tmp[x%10]++;
}while(x/=10);
do{
tmp[y%10]++;
}while(y/=10);
for(i=0;i<10;i++)
if(tmp[i]!
=used[i])
return0;
return1;
}
intcheck4(intx,intused[10])
{
do{
if(used[x%10]!
=0)
return0;
used[x%10]++;
}while(x/=10);
return1;
}
intmain()
{
inta,b,c,i,cnt=0,used[10];
for(c=1023;c<=9876;c++)
{
for(i=0;i<10;i++)
used[i]=0;
if(!
check4(c,used))
continue;
for(a=2;a<=98;a++)
{
if(c%a!
=0)
continue;
b=c/a;
if(a>b)
continue;
if(!
check(a,b,used))
continue;
printf("%d*%d=%d\n",a,b,c);
cnt++;
}
}
printf("Count=%d\n",cnt);
return0;
}
绳圈
今有100根绳子,当然会有200个绳头。
如果任意取绳头两两配对,把所有绳头都打结连接起来。
最后会形成若干个绳圈(不考虑是否套在一起)。
我们的问题是:
请计算最后将形成多少个绳圈的概率最大?
注意:
结果是一个整数,请通过浏览器提交该数字。
不要填写多余的内容。
(1)答案。
3
(2)编程思路。
设dp[i][j]表示i条绳结成j个圈的概率,c[i]表示i条绳的2i个端点配对的种数,有c[1]=1,c[i]=c[i-1]*(2i-1),
由于i条绳结成i个圈只有一种可能,即每条绳自己组成一个圈,故
有dp[i][i]=1/c[i]
进一步,i条绳结成j(2<=j
1)第i条绳跟自己组合成圈,其余i-1条绳组成j-1个圈;2)第i条绳与其他绳子的绳头组合,可将它与某条绳两个绳头结在一起后看成1条绳,这样i-1条绳构成j个圈。
顾有
dp[i][j]=(dp[i-1][j]*c[i-1]*(i-1)*2+dp[i-1][j-1]*c[i-1])/c[i]
再根据c[i]和c[i-1]的递推关系将c[i]和c[i-1]约去,得到递推式
dp[i][j]=(dp[i-1][j]*(2*i-2)+dp[i-1][j-1])/(2*i-1);
(3)源程序。
#include
intmain()
{
doubledp[101][101]={0};
dp[1][1]=1;
inti,j;
for(i=2;i<=100;i++)
{
for(j=1;j<=i;j++)
{
dp[i][j]=dp[i-1][j-1]/(2*i-1)+dp[i-1][j]*(2*i-2)/(2*i-1);
}
}
intans=0;
doublemaxR=0;
for(i=1;i<=100;i++)
{
if(dp[100][i]>maxR)
{
ans=i;
maxR=dp[100][i];
}
}
printf("%d\n",ans);
return0;
}
分糖果
有n个小朋友围坐成一圈。
老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:
每个小朋友都把自己的糖果分一半给左手边的孩子。
一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数。
反复进行这个游戏,直到所有小朋友的糖果数都相同为止。
你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。
【格式要求】
程序首先读入一个整数N(2接着是一行用空格分开的N个偶数(每个偶数不大于1000,不小于2)
要求程序输出一个整数,表示老师需要补发的糖果数。
例如:
输入
3
224
程序应该输出:
4
(1)编程思路。
我们用逐步求精的方法来分析这个问题的解决方法。
1)先写出程序的总体框架如下:
输入n个小孩的初始糖果数①;
While(n个小孩的糖果数不全相等②)
{
所有小孩同时把自己糖果的一半分给左边的小孩③;
糖的块数为奇数的小孩向老师补要一块,且补发颗数加1④;
}
输出结果信息
在这个总体框架中需要解决4个问题。
2)设定义一个整型数组a来保存10个小孩的糖果数,问题①就是需要输入n个数组元素的初始值,程序代码为:
for(i=0;iscanf(“%d”,&a[i]);
3)问题②需要判断n个小孩的糖果数是否相等,显然是一个操作序列,其判断结果是while循环的条件,因此将问题②抽象成一个函数AllEqual,该函数用来判断数组中所有元素的值是否都相等,如果都相等则返回1,否则返回0。
其函数原型为:
intAllEqual(intx[]);
而为判断一个数组中所有元素的值是否全相等,最简单的办法为将数组中的第2个数至最后一个数与第1个数相比较,只要它们中有一个不相等,就返回0(不全相等),如果比较完后,没有返回0,则它们全相等,返回1。
函数的定义为:
intAllEqual(intx[],intn)
{
inti;
for(i=1;iif(x[i]!
=x[0])return0;
return1;
}
4)问题③完成一次调整过程,所有小孩需要同时把自己糖果的一半分给左边的小孩,如下图所示。
图1一次调整过程示例图
由图看出(以n=10为例),
当i=1~9时,有a(i)=(a(i)+a(i-1))/2
i=0时,a(0)=(a(0)+a(9))/2
因此,很容易地想到可以写成如下的代码段:
a[0]=a[0]/2+a[n-1]/2;
for(i=1;ia[i]=a[i]/2+a[i-1]/2;
这样写是错误的,为什么呢?
因为先修改a[1],当计算a[2]时,用到的a[1]已经被修改了。
应该写成:
temp=a[n-1];
for(i=n-1;i>0;i--)
a[i]=a[i]/2+a[i-1]/2;
a[0]=a[0]/2+temp/2;
5)问题④可以用一个循环程序解决,对数组中的每个元素判断其奇偶性,如果为奇数,则将该元素值加1。
程序代码为:
for(i=0;iif(a[i]%2!
=0){a[i]++;ans++;}
至此,可以写出完整的源程序。
(2)源程序。
#include
intAllEqual(intx[],intn)
{
inti;
for(i=1;iif(x[i]!
=x[0])return0;
return1;
}
intmain()
{
intn,i,ans=0;
inta[100];
scanf("%d",&n);
for(i=0;iscanf("%d",&a[i]);
while(AllEqual(a,n)!
=1)
{
inttemp;
temp=a[n-1];
for(i=n-1;i>0;i--)
a[i]=a[i]/2+a[i-1]/2;
a[0]=a[0]/2+temp/2;
for(i=0;iif(a[i]%2!
=0)
{
a[i]++;ans++;
}
}
printf("%d\n",ans);
return0;
}
地宫取宝
X国王有一个地宫宝库。
是nxm个格子的矩阵。
每个格子放一件宝贝。
每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
【数据格式】
输入一行3个整数,用空格分开:
nmk(1<=n,m<=50,1<=k<=12)
接下来有n行数据,每行有m个整数Ci(0<=Ci<=12)代表这个格子上的宝物的价值
要求输出一个整数,表示正好取k个宝贝的行动方案数。
该数字可能很大,输出它对1000000007取模的结果。
例如,输入:
222
12
21
程序应该输出:
2
再例如,输入:
232
123
215
程序应该输出:
14
(1)编程思路。
采用记忆化搜索完成。
定义4维数组dp[51][51][15][15]。
设dp[x][y][num][val]表示在坐标(x,y)时拿了num件宝贝并且宝贝中价值最大的为val,其中1≤x≤n,1≤y≤m,num的初值为0,表示还没有拿到宝贝,val的初值本来应该为-1,表示此时手上还没有宝物(因为从题目数据说明中可以看出宝贝的价值可以为0),为了让val初始值为0,可以将输入的宝贝的价值统一加1,这样宝贝的最小价值为1(不是0)。
定义二维数组intmap[51][51]保存地宫各格子的宝贝价值。
采用倒推法列出状态转移方程,即把后面的情况种数不断的往前更新。
当map[x][y]>val时,
dp[x][y][num][val]=dp[x+1][y][num+1][map[x][y]]+dp[x][y+1][num+1][map[x][y]]
+dp[x+1][y][num][val]+dp[x][y+1][num][val];
当map[x][y]<=val时,
dp[x][y][num][val]=dp[x+1][y][num][val]+dp[x][y+1][num][val]。
在通过DFS搜索方式求数组dp的各元素值时,由于数组元素值dp[x][y][num][val]跟位置(x,y)、宝贝个数以及当前最大的宝贝价值有关,当重复遍历这个结点时,若dp[x][y][num][val]的值已经计算出来了,则直接应用无需重复递归计算。
为此,定义数组dp的全部元素的初始值为-1。
若计算时需要用到dp[x][y][num][val],此时dp[x][y][num][val]!
=-1,则无需重复调用,直接应用计算好的dp[x][y][num][val]元素值。
之所以初值定义为-1,是考虑到若路径不存在的情况(此时方案数应为0)。
(2)源程序。
#include
#include
#defineMOD1000000007
longlongdp[51][51][15][15];
intmap[51][51];
intn,m,k;
voiddfs(intx,inty,intnum,intval)
{
if(dp[x][y][num][val]!
=-1)
return;
dp[x][y][num][val]=0;
if(x==n&&y==m&&num==k)
{
dp[x][y][num][val]=1;
return;
}
if(map[x][y]>val&&num{
dfs(x,y,num+1,map[x][y]);
dp[x][y][num][val]+=dp[x][y][num+1][map[x][y]];
dp[x][y][num][val]%=MOD;
}
if(x{
dfs(x+1,y,num,val);
dp[x][y][num][val]+=dp[x+1][y][num][val];
dp[x][y][num][val]%=MOD;
}
if(y{
dfs(x,y+1,num,val);
dp[x][y][num][val]+=dp[x][y+1][num][val];
dp[x][y][num][val]%=MOD;
}
}
intmain()
{
scanf("%d%d%d",&n,&m,&k);
for(inti=1;i<=n;i++)
{
for(intj=1;j<=m;j++)
{
scanf("%d",&map[i][j]);
map[i][j]++;
}
}
memset(dp,-1,sizeof(dp));
dfs(1,1,0,0);
printf("%d\n",dp[1][1][0][0]);
return0;
}
小朋友排队
n个小朋友站成一排。
现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
每个小朋友都有一个不高兴的程度。
开始的时候,所有小朋友的不高兴程度都是0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。
当要求某个小朋友第k次交换时,他的不高兴程度增加k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
【数据格式】
输入的第一行包含一个整数n,表示小朋友的个数。
第二行包含n个整数H1H2…Hn,分别表示每个小朋友的身高。
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
例如,输入:
3
321
程序应该输出:
9
【样例说明】
首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
【数据规模与约定】
对于10%的数据,1<=n<=10;
对于30%的数据,1<=n<=1000;
对于50%的数据,1<=n<=10000;
对于100%的数据,1<=n<=100000,0<=Hi<=1000000。
(1)编程思路。
本题的实质是求一组数据中逆序数对的个数。
比如题目中的3,2,1,和3有关的逆序对为(3,2)和(3,1),和2有关的逆序对为(3,2)和(2,1),和1有关的逆序对为(3,1)和(2,1),为了完成排序,任何一个逆序对的两个元素都必须交换一次,于是可知,每个小朋友都完成了两次交换。
要求一个数组元素有关的逆序对个数,就是求它之前有几个大于它的元素(设为b1),之后有几个小于它的元素(设为b2),这样每个元素相关的逆序数对个数(也是需交换次数)为b1+b2。
根据数据规模与约定,若采用二重循环进行暴力搜索逆序对的个数,肯定会超时的。
因此,采用树状数组来解决本题。
树状数组实际上是由两部分组成:
数据数组(设为num)和统计数组(设为C)。
我们以数据数组num[