中国电子学会(CEIT)考评中心历届真题(含解析答案)
C语言软件编程等级考试三级 2020年09月
编程题五道 总分:100分
一、因子问题(20分)
任给两个正整数N、M,求一个最小的正整数a,使得a和(M-a)都是N的因子。
时间限制: 10000ms
内存限制: 65536kb
输入
包括两个整数N、M。N不超过1,000,000。输出
输出一个整数a,表示结果。如果某个案例中满足条件的正整数不存在,则在对应行输出-1
样例输入
c
35 10
样例输出
c
5
c
#include <stdio.h> // 引入标准输入输出库,用于使用scanf和printf函数
int main() { // 主函数入口
int i,m, n; // 声明三个整型变量i, m, n
scanf("%d %d", &n, &m); // 从标准输入读取两个整数,并分别赋值给n和m
// 使用枚举法来查找满足条件的i
for(i = 1; i < n; i++) { // 初始化i为1,并在每次迭代后递增,直到i大于n时停止
if(n % i == 0 && n % (m - i) == 0) { // 检查n是否能被i整除,并且n是否能被(m-i)整除
printf("%d", i); // 如果满足条件,打印i的值
return 0; // 退出程序,返回0表示正常结束
}
}
printf("-1"); // 如果循环结束后没有找到满足条件的i,则打印-1
return 0; // 退出程序,返回0表示正常结束
}
/*
此代码的目的是找到一个整数i,使得n可以被i和(m-i)整除。
如果找到了这样的i,则打印出i并结束程序;如果没有找到,
则打印-1并结束程序。
*/
二、质数的和与积(20分)
两个质数的和是S,它们的积最大是多少?
时间限制: 10000ms
内存限制: 65536kb
输入
一个不大于10000的正整数S,为两个质数的和。输出
一个整数,为两个质数的最大乘积。数据保证有解。
样例输入
c
50
样例输出
c
589
c
#include <stdio.h> // 引入标准输入输出库,用于printf和scanf函数
#include <math.h> // 引入数学库,用于sqrt函数
bool judge(int x){ // 定义一个函数,用于判断一个整数x是否为素数
int i; // 定义循环变量i
if(x==2)
return false; // 如果x为2,返回false,因为2是唯一的偶数素数
for(i=2; i<=sqrt(x); i++) // 从2开始,到x的平方根(包含),遍历所有可能的因子
if(x%i==0) // 如果x能被i整除
return false; // 则x不是素数,返回false
return true; // 如果x不能被2到其平方根之间的任何数整除,那么x是素数,返回true
}
int main() { // 主函数入口
int i,s; // 定义循环变量i和输入变量s
scanf("%d" ,&s); // 从标准输入读取一个整数,并存储在变量s中
for(i=s/2; i>=2; i--){ // 从s/2开始,递减到2,遍历所有可能的数
if(judge(i)&&judge(s-i)){ // 判断i和s-i是否都是素数
printf("%d \n",i*(s-i)); // 如果是,输出它们的乘积,并结束程序
return 0;
}
}
printf("-1"); // 如果找不到符合条件的素数对,输出-1
return 0; // 结束程序
}
三、扩号匹配问题(20分)
在某个字符串(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左括号用"$"
标注,不能匹配的右括号用"?"
标注.
时间限制: 3000ms
内存限制: 65536kb
输入
输入包括多组数据,每组数据一行,包含一个字符串,只包含左右括号和大小写字母,字符串长度不超过100
输出
对每组输出数据,输出两行,第一行包含原始输入字符,第二行由"$"
,"?"
和空格组成,"$"
和"?"
表示与之对应的左括号和右括号不能匹配。
样例输入
c
((ABCD(x)
)(rttyy())sss)(
样例输出
c
((ABCD(x)
$$
)(rttyy())sss)(
? ?$
c
#include <stdio.h> // 引入标准输入输出头文件,这样我们可以使用scanf和printf等函数
#include <string.h> // 引入字符串处理头文件
#define N 105 // 定义一个常量N,用于指定数组的最大长度
int main() { // 主函数开始
int i,j,n; // 定义三个整型变量i, j, n
char s[N] = " "; // 定义一个字符数组s,长度为N,初始化为一个空格
int flag[N]; // 定义一个整型数组flag,用于标记括号的位置
while (scanf("%s", s)!= EOF) { // 使用scanf读取字符串,直到遇到文件结束符EOF
n = strlen(s); // 获取字符串s的长度
// 将字符串中的括号转换为对应的标记
for (i = 0; i < n; i++){
if (s[i]== '(') // 如果是左括号,标记为1
flag[i]= 1;
else if (s[i]== ')') // 如果是右括号,标记为-1
flag[i]= -1;
else
flag[i] = 0; // 其他字符标记为0
}
// 遍历字符串,处理右括号
for (i = 0; i < n; i++){
if (flag[i] == -1){
// 如果当前字符是右括号,向前搜索匹配的左括号
for (j = i - 1; j >= 0; j--){
if (flag[j] == 1) {
// 如果找到匹配的左括号,将两个括号标记为0
flag[i] = 0;
flag[j] = 0;
break; // 跳出内层循环
}
}
}
}
printf("%s\n",s); // 输出处理前的字符串
// 根据标记数组打印结果
for (i = 0; i < n; i++){
if (flag[i] == 0)
printf(" "); // 如果是空格或已匹配的括号,输出空格
else if(flag[i]== 1)
printf("$"); // 如果是左括号,输出$
else if (flag[i]== -1)
printf("?"); // 如果是未匹配的右括号,输出?
}
printf("\n"); // 输出换行符
}
return 0; // 主函数返回0,表示程序正常结束
}
/*
程序的目的是处理用户输入的字符串,其中包含左括号'('和右括号')'。
程序会标记出每个括号的位置,并检查是否有未匹配的右括号。
如果有未匹配的右括号,程序会在输出时将其替换为'?',
而匹配的括号对会被替换为空格。左括号会被替换为'$'。
*/
四、吃糖果(20分)
名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名(盒内共有N块巧克力,20>N>0)。妈妈告诉名名每天可以吃一块或者两块巧克力。假设名名每天都吃巧克力,问名名共有多少种不同的吃完巧克力的方案。
例如:
如果N=1,则名名第1天就吃掉它,共有1种方案;
如果N=2,则名名可以第1天吃1块,第2天吃1块,也可以第1天吃2块,共有2种方案;
如果N=3,则名名第1天可以吃1块,剩2块,也可以第1天吃2块剩1块,所以名名共有2+1=3种方案;
如果N=4,则名名可以第1天吃1块,剩3块,也可以第1天吃2块,剩2块,共有3+2=5种方案。
现在给定N,请你写程序求出名名吃巧克力的方案数目。
时间限制: 1000ms
内存限制: 65536kb
输入
输入只有1行,即整数N。
输出
输出只有1行,即名名吃巧克力的方案数。
样例输入
c
4
样例输出
c
5
c
#include<stdio.h> // 引入标准输入输出库,这样我们可以使用scanf和printf等函数
// 定义一个函数func,它接受一个整数n作为参数,并返回斐波那契数列中第n项的值
int func(int n){
if(n==1) // 如果n等于1
return 1; // 返回斐波那契数列的第1项,即1
if(n==2) // 如果n等于2
return 2; // 返回斐波那契数列的第2项,即2
// 如果n不是1也不是2,那么返回前两项的和,即func(n-1) + func(n-2)
return func(n-1)+func(n-2);
}
// main函数,程序的入口点
int main() {
int n; // 定义一个整数变量n,用于存储用户输入的数字
scanf("%d",&n); // 使用scanf函数从标准输入读取一个整数,并将其存储在变量n中
printf("%d",func(n)); // 使用printf函数输出斐波那契数列中第n项的值
return 0; // 表示程序正常结束
}
/*
实现是基于递归的,对于较大的n值,它的效率会非常低,因
为它会重复计算很多相同的子问题。在实际应用中,
通常会使用其他方法来提高计算斐波那契数列的效率,
比如动态规划或缓存已计算的值。
*/
五、铺砖(20分)
对于一个2行N列的走道。现在用1*2
,2*2
的砖去铺满。问有多少种不同的方式。
时间限制: 3000ms
内存限制: 131072kb
输入
整个测试有多组数据,请做到文件底结束。每行给出一个数字N,0 <=n<= 250
输出
如题
样例输入
c
2
8
12
100
200
样例输出
c
3
171
2731
845100400152152934331135470251
1071292029505993517027974728227441735014801995855195223534251
c
#include <stdio.h> // 引入标准输入输出库,这样我们可以使用scanf和printf等函数
#include <string.h> // 引入字符串处理头文件
// 大数相加函数
void Ladd(const char *a, const char *b, char *res) {
int an, bn, k, f, i, j;
int af[300] = {0}, bf[300] = {0}, c[300] = {0};
// 获取字符串a和b的长度
an = strlen(a);
bn = strlen(b);
// k为较长的字符串长度
k = an > bn ? an : bn;
// 初始化进位标志为0
f = 0;
// 将字符串a和b转换为整数数组af和bf
for (i = 0; i < an; i++)
af[i] = a[an - i - 1] - '0';
for (i = 0; i < bn; i++)
bf[i] = b[bn - i - 1] - '0';
// 执行大数相加
for (i = 0; i < k; i++) {
c[i] += (af[i] + bf[i]) % 10; // 个位数相加
c[i + 1] += (af[i] + bf[i]) / 10; // 进位
}
// 如果最高位有进位,则k增加1
if (c[i] != 0)
k++;
// 将结果数组c转换为字符串并存储到res中
for (i = k - 1, j = 0; i >= 0; i--) {
res[j++] = c[i] + '0';
}
}
char dp[300][300]; // 存储斐波那契数列变种的数组
int main() {
int n;
char res[300];
// 初始化前两个数字
strcpy(dp[0], "1");
strcpy(dp[1], "1");
strcpy(dp[2], "3");
// 根据公式d[i] = d[i-1] + d[i-2] * 2推导数列
// 计算斐波那契数列的变种
for (int i = 3; i <= 250; i++) {
memset(res, 0, sizeof(res)); // 清零结果字符串
Ladd(dp[i - 2], dp[i - 2], res); // d[i-2]的两倍
Ladd(dp[i - 1], res, res); // 加上d[i-1]
strcpy(dp[i], res); // 存储结果
}
// 从标准输入读取n,并打印dp[n]直到n为0
while (true) {
scanf("%d", &n);
if (n == 0)
break;
printf("%s\n", dp[n]);
}
return 0;
}
/*
程序的主要逻辑是计算一个特定斐波那契数列的变种,其中每个数字是前两个数字之和的两倍。
程序首先初始化前两个数字,然后使用循环计算后续的数字,并将它们存储在dp数组中。然后,
程序进入一个无限循环,不断从标准输入读取一个数字n,并打印出dp[n]的值,直到用户输入0为止。
*/