真题解析 | CCF CSP-J 2019 入门级 C++语言真题及答案

一、单项选择题(共15题,每题2分,共计30分;每题有且仅有一个正确选项)

1.中国的国家顶级域名是( )

A. .cn          B. .ch          C. .chn          D. .China

答案:A

题目分析:常识题。

2.二进制数11 1011 1001 0111和01 0110 1110 1011进行逻辑与运算的结果是( )

A.01 0010 1000 1011          B.01 0010 1001 0011

C.0l 0010 1000 0001          D.01 0010 1000 0011

答案:D

题目分析:聪明的小朋友可以发现4个答案前面2串数值都是一样的,直接跳过,第三串有一个不一样判断一下,随后判断最后一串即可,不需要全部计算一次。与运算就是&,当且仅当两个计算量同一位都为1的时候该位结果才为1,反之为0。

3.一个32位整型变量占用()个字节。

A. 32          B.128          C. 4          D.8

答案:C

题目分析:Byte(字节) = 8 bit(位) 32/8=4

4.若有如下程序段,其中s、a、b、c均已定义为整型变量,且a、c均已赋值(c大于0)

s=a
for(b= 1: b< c: b++)s=s-1

则与上述程序段功能等价的赋值语句是()

A.s=a-c;          B.s=a-b;          C.s=s-c;          D.s=b-c;

答案:A

题目分析:s初始化为a; for循环执行c次,每次s减1,共减c,所以s=a-c,考察for循环的应用。

5.设有100个已排好序的数据元素,采用折半查找时,最大比较次数为()

A.7          B.10          C.6          D.8

答案:A

题目分析:折半查找。

        首先将待查记录所在范围缩小一半,然后再缩小一半,即对100个元素进行折半查找,第一次比较范围缩小到50,第二次缩小到25,第三次缩小到17,第四次缩小到7,第五次缩小到4,第六次缩小到2,最多七次就可以查找到所要元素。

6.链表不具有的特点是()

A.插入删除不需要移动元素          B.不必事先估计存储空间

C.所需空间与线性表长度成正比          D.可随机访问任一元素

答案:D

题目分析:链表

        链表是链式存储,需要从头开始遍历读取数据——顺序访问,不可直接读取——随机访问。

7.把8个同样的球放在5个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的分法?( )提示:如果8个球都放在一个袋子里,无论是哪个袋子,都只算同一种分法。

A.22          B.24          C.18          D.20

答案:C

题目分析:组合排列

        假设有4个袋子空着不放,那么就有1种分法(全部放在一个袋子里),由于不考虑顺序,那么我们必须确保n+1位的数字要>=n,无法满足的时候n-1位置的数字+1便可!

假设有3个袋子空着不放,那么有4种方法(1,7),(2,6),(3,5)(4,4),以此类推。。。

假设有2个袋子不放,有5种分法,(1,1,6),(1,2,5),(1,3,4),(2,2,4),(2,3,3);

假设有1个袋子不放,有5种分法,(1,1,1,5),(1,1,2,4),(1,1,3,3),(1,2,2,3),(2,2,2,2);

假设有0个袋子不放,有3种分法。(1,1,1,1,4),(1,1,1,2,3);

->总共[1+4+5+5+3  = 18]种!

8.一棵二叉树如右图所示,若采用顺序存储结构,即用一维数组元素存储该二叉树中的结点(根结点的下标为1,若某结点的下标为i,则其左孩子位于下标2i处、右孩子位于下标2i+1处),则该数组的最大下标至少为()

A.6          B.10          C.15          D.12

答案:C

题目分析:二叉树左右孩子

        根据题意,节点1下标为1,节点2下标为2,节点3下标为3,节点4下标为2*节点3=6,节点5下标为2*节点3+1=7,因此最后的节点6最小也要2*节点5+1=2*7+1=15。

9.100以内最大的素数是()。

A.89          B.97          C.91          D.93

答案:B

题目分析:素数

        素数就是只能被1和自己整除,97最大且为素数。

10.319和377的最大公约数是()。

A.27          B.33          C.29          D.31

答案:C

题目分析:gcd

        使用辗转相除法计算(319,377)=(319,58)=(58,29) = 29。

11.新学期开学了,小胖想减肥,健身教练给小胖制定了两个训练方案。方案一:每次连续跑3公里可以消耗300千卡(耗时半小时);方案二:每次连续跑5公里可以消耗600千卡(耗时1小时)。小胖每周周一到周四能抽出半小时跑步,周五到周日能抽出一小时跑步。另外,教练建议小胖每周最多跑21公里,否则会损伤膝盖。请问如果小胖想严格执行教练的训练方案,并且不想损伤膝盖,每周最多通过跑步消耗多少千卡?()

A.3000          B.2500          C.2400          D.2520

答案:C

题目分析:优化问题,线性规划

        设方案1,2各i,j天,由题意,3*i+5*j<=21,i+j<=7,i<=3.求300*i+600*j的最大值。枚举所有情况当i=2,j=3时,最大值2400。

12.一副纸牌除掉大小王有52张牌,四种花色,每种花色13张。假设从这52张牌中随机抽取13张纸牌,则至少( )张牌的花色一致

A.4          B.2          C.3          D.5

答案:A

题目分析:抽屉原理

        最坏情况是每种花色都只有3张牌,这样4种花色中最多只能有3张一致。因此,至少有4张纸牌的花色是一致的。因为13张牌需要分到4种花色中,所以至少有一种花色会有4张或更多的牌。也就是至少4张一样花色。

13.一些数字可以颠倒过来看,例如0、1、8颠倒过来还是本身,6颠倒过来是9,颠倒过来看还是6,其他数字颠倒过来都不构成数字。类似的,一些多位数也可以颠倒过来看,比如106颠倒过来是901。假设某个城市的车牌只由5位数字组成,每一位都可以取0到9。请问这个城市最多有多少个车牌倒过来恰好还是原来的车牌?()

A.60          B.125          C.75          D.100

答案:C

题目分析:考察乘法原理

        第1,2位有5种选法(0,1,6,8,9),第三位有三种0,1,8,第4,5位由前两位决定,所以答案位5*5*3=75。

14.假设一棵二叉树的后序遍历序列为 DGJHEBIFCA,中序遍历序列为 DBGEHJACIF,则其前序遍历序列为( )。

A. ABCDEFGHIJ          B. ABDEGHJCFI

C. ABDEGJHCFI          D. ABDEGHJFIC

答案:B

题目分析:考察二叉树的遍历

        后序遍历决定根是A,中序遍历中看A的左边DBGEH是左子树,右边CIF是右子树,依次类推可画出完整的树,再求先序遍历。

15.以下哪个奖项是计算机科学领域的最高奖?()

A.图灵奖          B.鲁班奖          C.诺贝尔奖          D.普利策奖

答案:A

题目分析:考察常识问题。

二、阅读程序(程序输入不超过数组或字符串定义的范围:判断题正确填√,错误填×:除特殊说明外,判断题1.5分,选择题3分,共计40分)

1.

判断题

1)输入的字符串只能由小写字母或大写字母组成。()

答案:×

题目分析:根据st[i-1] = c - 'a' + 'A‘可以看出,这是一个转换小写字母变为大写的过程,因此c一定是小写字母。

2)若将第8行的“i=1”改为“i=0”,程序运行时会发生错误()

答案:√

题目分析:不能对0取余操作,错误。

3)若将第8行的“i<=n”改为“i*i<=n”,程序运行结果不会改变()

答案:×

题目分析:求约数不是判断质数,i*i<=n只能取到n的前半部分约数。

4)若输入的字符串全部由大写字母组成,那么输出的字符串就跟输入的字符串一样。()

答案:√

题目分析:按题意说明即可判断。

选择题

5)若输入的字符串长度为18,那么输入的字符串跟输出的字符串相比至多有()个字符不同。

A.18           B.6           C.10           D.1

答案:B

题目分析:约数个数定理求约数个数。18的约数是:1,2,3,6,9,18。所以最多判定6次。

6)若输入的字符串长度为(),那么输入的字符串跟输出的字符申相比,至多有36个字符不同。

A.36           B.100000           C.1           D.128

答案:B

题目分析:和上题同理。枚举4个选项。36有9个约数,1有1个约数,128有8个约数。选B。100000有36个约数。

2.

假设输入的n和m都是正整数,x和y都是在[1,n]的范围内的整数,完成下面的判断题和单选题

判断题

1)当m>0时,输出的值一定小于2n。()

答案:√

题目分析:按照题意,a数组和b数组赋值为0,a[x] < y && b[y] < x成立,累计计算求和,最终结果肯定小于2n。

2)执行完第27行的“++ans”时,ans一定是偶数。()

答案:×

题目分析:不一定,可以举例求出ans不是偶数的情况。

3) a[i]和b[i]不可能同时大于0。()

答案:×

题目分析:举例即可找到反例。

4)若程序执行到第13行时,x总是小于y,那么第15行不会被执行。()

答案:×

题目分析:同样举例可以实现。

选择題

5)若m个x两两不同,且m个y两两不同,则输出的值为()

A. 2n-2m           B.2n+2           C.2n-2           D.2n

答案:A

题目分析:根据题意,m次循环中会有2m个位置的值会变化,ans=2n-2m。

6)若m个x两两不同,且m个y都相等,则输出的值为()

A.2n-2           B.2n           C.2m           D.2n-2m

答案:A

题目分析:如果m个x各不相同,循环里面的if都不会执行。对数组a,b赋值,只修改了2个位置。也可举例 【3 3,3 3,2 3,1 3】,答案是4。

3.

分析:分治算法。左右两边找答案,然后求运算。

判断题

1)如果a数组有重复的数字,则程序运行时会发生错误。()

答案:×

题目分析:分析代码,有重复的数字不会导致程序运行出错。

2)如果b数组全为0,则输出为0.()

答案:√

题目分析:如果b数组是0,递归推出条件l>r返回0,根据return lres + rres + depth * b[mink];返回结果总是0。

选择题

3)当n=100时,最坏情况下,与第12行的比较运算执行的次数最接近的是()

A.5000           B.6000           C.6           D.100

答案:A

题目分析:最坏情况下a有序,总是求mink和min最小值,需要判断100+99+98+...+2+1 =5050,选A。

4)当n=100时,最好情况下,与第12行的比较运算执行的次数最接近的是()

A.100           B.6           C.5000           D.600

答案:D

题目分析:最好情况每次都二分,总次数为100,层数为 6<log2100<7,总次数约为[6*100,7*100],选D。

5)当n=10时,若b数组满足,对任意0≤i<n,都有b[i]=i+1,那么输出最大为()

A.386           B.383           C.384           D.385

答案:D

题目分析:n=10,深度最大是10,根据代码:1*b[0]+2*b[1]+...+10*b[9]=1*1+2*2+3*3+...+10*10=385。

6)(4分)当n=100时,若b数组满足,对任意0≤i<n,都有b[i]=1, 那么输出最小为()

A.582           B.580           C.579           D.581

答案:B

题目分析:b[i]=1,即求一个100节点的完全二叉树,节点深度之和最小为多少。画图后,计算为1*1+2*2+4*3+8*4+16*5+32*6+37*7=580。

三、完善程序(单选题,每小题3分,共计30分)

1.

#include <cstdio>
using namespace std;
int n;
const int max_size = 1 << 10;

int res[max_size][max_size];

void recursive(int x, int y, int n, int t) {
    if (n == 0) {
        res[x][y] = ①;
        return;
    }
    int step = 1 << (n - 1);
    recursive(②, n - 1, t);
    recursive(x, y + step, n - 1, t);
    recursive(x + step, y, n - 1, t);
    recursive(③, n - 1, !t);
}

int main() {
    scanf("%d", &n);
    recursive(0, 0, ④);
    int size = ⑤;
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++)
            printf("%d", res[i][j]);
        puts("");
    }
    return 0;
}	

① 处应填( )

A.n%2          B.0          C.t          D.1

答案:C

题目分析:(猜的话,变量t没有用过。)递归退出判断,参数t的赋值能发现是经常做取反操作。赋值和n没有必然联系,错误。选C。

② 处应填( )

A.x-step,y-step           B.x,y-step

C.x-step,y           D.x,y

答案:D

题目分析:四个方向,x,y是当前坐标。根据下面参数,参数分别是x,y;x,y+step;x+step,y;x+step,y+step。

③ 处应填( )

A. x-step,y-step           B. x+step,y+step

C. x-step,y           D. x,y-step

答案:B

④ 处应填( )

A.n-1,n%2           B.n,0           C.n,n%2           D.n-1,0

答案:B

题目分析:第一次调用recursive函数,n是矩阵规模,初始为n,t是取反次数,所以t初始为0或者1。

1)⑤ 处应填( )

A.i<<(n+1)           B.1<<n           C.n+1           D.1<<(n-1)

答案:B

题目分析:size是输出矩阵的边长,2^n,位运算是1<<n。

2. (计数排序)计数排序是一个广泛使用的排序方法。下面的程序使用双关键字计数排序,对 n 对 10000 以内的整数,从小到大排序。

例如有三对整数(3,4)、(2,4)、(3,3),那么排序之后应该是(2,4)、(3,3)、(3,4)。

输入第一行为 n,接下来 n 行,第 i 行有两个数 a[i] 和 b[i],分别表示第 i 对整数的第一关键字和第二关关键字。

从小到大排序后输出。

提示:应先对第二关键字排序,再对第一关键字排序。数组 ord[]存储第二关键字排序的结果,数组 res[]存储双关键字排序的结果。

试补全程序

#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10000000;
const int maxs = 10000;

int n;
unsigned a[maxn], b[maxn],res[maxn], ord[maxn];
unsigned cnt[maxs + 1];
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) 
        scanf("%d%d", &a[i], &b[i]);
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i < n; ++i)
        ①; // 利用 cnt 数组统计数量
    for (int i = 0; i < maxs; ++i) 
        cnt[i + 1] += cnt[i];
    for (int i = 0; i < n; ++i)
        ②; // 记录初步排序结果
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i < n; ++i)
        ③; // 利用 cnt 数组统计数量
    for (int i = 0; i < maxs; ++i)
        cnt[i + 1] += cnt[i];
    for (int i = n - 1; i >= 0; --i)
        ④ // 记录最终排序结果
    for (int i = 0; i < n; i++)
        printf("%d %d", ⑤);

    return 0;
}

计数排序知识补习:
### 示例:
假设我们有一个待排序数组为 $[4, 4, 3]$,现在我们来演示如何使用计数排序对这个数组进行排序。

1. 找出待排序数组中的最大值和最小值,确定计数数组的大小。
2. 统计每个元素出现的次数,得到计数数组为 $[0, 0, 0, 1, 2]$。
3. 对计数数组进行累加操作,得到 $[0, 0, 0, 1, 3]$。
4. 遍历待排序数组,根据计数数组中的累加值,将元素放置到正确的位置上。(比较复杂看下面例题第②)

1)①处应填()

题目分析:此处是基础的计数排序第一步得到每个元素出现的次数,首先取出v=b[i]的值,使得cnt[v] += 1,得到各个元素的在计数数组中的累计值。合起来就是++cnt[b[i]],所以选择B。

2)②处应填()

题目分析:

第②步:得到按照第二关键字排序的结果,使用ord[i..n]记录结果。

在此之前,cnt进行了计数排序的第3步骤,累加操作,故:
b = [4, 4, 3]
cnt = [0, 0, 0, 1, 1+2=3] 
-------------------------------
当i=0,的时候初始状态为:
cnt = [0, 0, 0, 1, 3]
ord = [0, 0, 0, 0]

记录结果按照以下步骤来进行,以第一个迭代值b[0]举例子:
首先遍历b[i..n],取出迭代值v = b[i],当i=0时,v = b[0] = 4,
然后取出cnt[v],也就是 cnt[4] = 3, 
取出后,cnt[v] -= 1,此时cnt[4] = 2,
把ord[2] = i,即 ord[2] = 0
此时 ord = [0, 0, $0],
整体步骤就是:ord[--cnt[b[i]]]= i ,所以选择D。
重复以上的步骤,
-------------------------------
当i=1的时候,
cnt = [0, 0, 0, 1, 2]
ord = [0, 0, $0]

v = b[1]= 4
取出cnt[4] = 2,放入ord,cnt[4] -= 1;
即 ord[2] = i,即 ord[2] = 1
此时 ord = [0, 1, $0]
--------------------------------
当i=2的时候,

cnt = [0, 0, 0, 1, 1]

ord = [0, 1, $0, 0]

v = b[2]= 3
取出cnt[3] = 1,cnt[3] -=1  = 0, 放入ord,此时cnt[3] = 0
即 ord[0] = i,即 ord[0] = 2
此时 
ord = [2, 1, $0]
cnt = [0, 0, 0, 0, 1]
--------------------------------
这个结果排名表明b的排序结果是倒过来[3,4,4],正确的

3)③处应填()

题目分析:对第一关键字进行计数,不必多说。

4)④处应填()

题目分析:第④题,为本题最难最关键的,如何根据第二关键字排序结果,继续第一关键字排序,进行二次排序。

我们先来看看第一次排序的操作:ord[--cnt[b[i]]] = i。
如果我们把ord换成res,b换成a数组,会发生什么?
res[--cnt[a[i]]] = i
很明显这不是正确答案,因为这没有基于第一次排序的结果,想要基于第一次排序,那么第一次排序的结果cnt和ord是必须用上的,
如何用上呢?其实很简单!
大家发现没有i是什么?
是原始数组(3,4)、(2,4)、(3,3)的索引,他是没有排过序的,是a数组和b数组公用的,所以我们需要让a数组的索引,变成排好序的b数组索引,而不是0->1->2,应该是2->1->0,

根据ord = [2, 1, $0]可知“

此时数组为(3,3),(2,4),(3,4)

直接把 i 全部替换为 ord[i] 不就是我们的第一排序结果。因此,这就是基于此进行第二次排序。很简单,但是出题者故意把代码复杂化了,就是按照b数组排序一次,然后用b数组的结果按照a数组再排序一次而已。

此时:由于i=ord[i]因此,a[i] = [3, 2, 3],a[ord[i]] = [3,2,3], ord = [2, 1, 0]
当i=0的时候,取值是ord[0] =2,
当i=1的时候,取值是ord[1] =1,
当i=2的时候,取值是ord[2] =0

所以让i = ord[i] 之后,结果如下:
res[--cnt[a[ord[i]]]] = ord[i]
选择A

5) ⑤处应填()

题目分析:ord和res都是同样的数组,同样的用法。[2,1 0]也就是0的索引应该排在最后的位置,也就是第3的位置,1索引排在第2的位置,3的索引也就是0,就是第1的位置。NOTE:数组是从0开始的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大气层煮月亮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值