CSP-J1 2019

T1

中国的国家顶级域名是

  • A. cn
  • B. ch
  • C. chn
  • D. china
答案

A

域名级数是指一个域名由多少级组成,域名的各个级别被“.”分开,最右边的为顶级域名。顶级域名,又称一级域名,常见的有“.com”、“.org”、“.net”、“.cn”等,二级域名就是在一级域名前再加一级,如“baidu.com”。

T2

二进制数 11101110010111 和 01011011101011 进行按位与运算的结果是

  • A. 01001010001011
  • B. 01001010010011
  • C. 01001010000001
  • D. 01001010000011
答案

D

image

T3

一个 32 位整型变量占用多少个字节

  • A. 32
  • B. 128
  • C. 4
  • D. 8
答案

C

1 个字节是 8 位二进制

T4

若有如下程序段,其中 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

T5

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

  • A. 7
  • B. 10
  • C. 6
  • D. 8
答案

A

T6

链表不具有的特点是

  • A. 插入删除不需要移动元素
  • B. 不必事先估计存储空间
  • C. 所需空间与线性表长度成正比
  • D. 可随机访问任一元素
答案

D

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。由于不必须按顺序存储,链表在插入的时候可以达到 O(1) 的复杂度,但是查找一个结点或者访问特定编号的结点则需要 O(n) 的时间。
使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

T7

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

  • A. 22
  • B. 24
  • C. 18
  • D. 20
答案

C

4 个空袋:8
3 个空袋:1+7,2+6,3+5,4+4
2 个空袋:1+1+6,1+2+5,1+3+4,2+2+4,2+3+3
1 个空袋:1+1+1+5,1+1+2+4,1+1+3+3,1+2+2+3,2+2+2+2
没有空袋:1+1+1+1+4,1+1+1+2+3,1+1+2+2+2

T8

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

  • A. 6
  • B. 10
  • C. 15
  • D. 12
答案

C

image

T9

100 以内最大的素数是

  • A. 89
  • B. 97
  • C. 91
  • D. 93
答案

B

T10

319 和 377 的最大公约数是

  • A. 27
  • B. 33
  • C. 29
  • D. 31
答案

C

T11

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

  • A. 3000
  • B. 2500
  • C. 2400
  • D. 2520
答案

C

跑 3 个 1 小时和 2 个半小时,总计 21 公里,2400 千卡热量

T12

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

  • A. 4
  • B. 2
  • C. 3
  • D. 5
答案

A

抽屉原理:13 张,4 种花色,3 套 4 种花色再加 1 张

T13

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

  • A. 60
  • B. 125
  • C. 75
  • D. 100
答案

C

第 1、2 位有(0、1、8、6、9)五个数字,第 3 位有(0、1、8)三个数字,第 4、5 位由第 1、2 位决定(如第 1 位 6,则第 5 位 9),5*5*3=75

T14

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

  • A. ABDCEFGHIJ
  • B. ABDEGHJCFI
  • C. ABDEGJHCFI
  • D. ABDEGHJFIC
答案

B

image

相关习题:P1030 求先序排列

T15

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

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

A

T16

#include <cstdio>
#include <cstring>
using namespace std;
char st[100];
int main() {
scanf("%s", st);
int n = strlen(st);
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
char c = st[i - 1];
if (c >= 'a') st[i - 1] = c - 'a' + 'A';
}
}
printf("%s", st);
return 0;
}
程序分析

输入一个字符串,对于序号是 n 的约数的字符,ASCII 码减 32(如果原本是小写字母,会转成大写字母)

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

答案

错误

2. 若将第 8 行的i = 1改为i = 0,程序运行时会发生错误。

答案

正确

除法的除数为 0,会产生浮点数错误

3. 若将第 8 行的i <= n改为i * i <= n,程序运行结果不会改变。

答案

错误

假设 n=16,修改后,i=8 不会被处理

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

答案

正确

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

  • A. 18
  • B. 6
  • C. 10
  • D. 1
答案

B

i=1,2,3,6,9,18

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

  • A. 36
  • B. 100000
  • C. 1
  • D. 128
答案

B

100000=25×55
计算幂次,则 2 有 0-5 一共 6 种取法,5 有 0-5 一共 6 种取法,6×6=36

T17

#include <cstdio>
using namespace std;
int n, m;
int a[100], b[100];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
a[i] = b[i] = 0;
for (int i = 1; i <= m; ++i) {
int x, y;
scanf("%d%d", &x, &y);
if (a[x] < y && b[y] < x) {
if (a[x] > 0)
b[a[x]] = 0;
if (b[y] > 0)
a[b[y]] = 0;
a[x] = y;
b[y] = x;
}
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] == 0)
++ans;
if (b[i] == 0)
++ans;
}
printf("%d\n", ans);
return 0;
}

假设输入的 n 和 m 都是正整数,x 和 y 都是在 [1,n] 的范围内的整数

程序分析

image

有 a、b 两组元素,两组元素之间相互两两对应。初始时所有元素都和另一组的 0 对应。

image

每次考察 a 组的第 x 个元素和 b 组的第 y 个元素,如果新的配对方案使与 a[x] 和 b[y] 配对的两个端点都向右移动(这两个元素之前的配对交叉了),就重新配对。蓝线为新配对方案,红线为原配对方案。

image

最后输出未配对元素数量。

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

答案

正确

至少会有一对配对成功

2. 执行完第 27 行的++ans时,ans 一定是偶数

答案

错误

本题相当于两个数组间有若干条线有对照关系,最终的 ans 必定为偶数,但是在 for 循环的统计过程中不一定。如当 i=1 时,执行完第 27 行,ans 是奇数
image

3. a[i] 和 b[i] 不可能同时大于 0

答案

错误

令 m=1,输入 x=2,y=2 时,a[i] 和 b[i] 同时为 2

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

答案

错误

如果 x 之前已经配对过,则会更新,如:(1,2)、(1,3)

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

  • A. 2n-2m
  • B. 2n+2
  • C. 2n-2
  • D. 2n
答案

A

因为 m 个 x 和 m 个 y 互不相同,会成功配对 m 次(配对前各自初始值为 0,配对后不会更新)。m 次循环中会有 2m 个位置的值发生变化,ans=2n-2m

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

  • A. 2n-2
  • B. 2n
  • C. 2m
  • D. 2n-2m
答案

A

x 和 y 配对时每次都会清理掉之前的配对(或者不更新配对),最终只会产生一组配对,所以和 0 配对的元素数量为 2n-2

T18

#include <iostream>
using namespace std;
const int maxn = 10000;
int n;
int a[maxn];
int b[maxn];
int f(int l, int r, int depth) {
if (l > r)
return 0;
int min = maxn, mink;
for (int i = l; i <= r; ++i) {
if (min > a[i]) {
min = a[i];
mink = i;
}
}
int lres = f(l, mink - 1, depth + 1);
int rres = f(mink + 1, r, depth + 1);
return lres + rres + depth * b[mink];
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i)
cin >> b[i];
cout << f(0, n - 1, 1) << endl;
return 0;
}
程序分析

将数组 b 根据数组 a 的值构造成一棵二叉树,二叉树的节点是 b 数组的元素。每次在序列 a 中选择值最小且靠前的元素作为根,根左侧的序列构建左子树,根右侧的序列构建右子树,递归求解。最后求每个节点值 b[i] 乘深度 depth 的和。
image

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

答案

错误

每次是找第一次出现的最小值,重复不影响

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

答案

正确

ans 是求每个节点值 b[i] 乘深度 depth 的和

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

  • A. 5000
  • B. 600
  • C. 6
  • D. 100
答案

A

最坏情况为每次的 min 都在最左或最右,一次只能构建单侧子树,每层只少一个点。则总比较次数为 100+99+98+......+1=5050

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

  • A. 100
  • B. 6
  • C. 5000
  • D. 600
答案

D

最好情况是每次 min 都在序列中间,刚好平分两个子树,则深度大约为 log21006,每层大概执行 100 次

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

  • A. 386
  • B. 383
  • C. 384
  • D. 385
答案

D

最大值为权值最大的深度最深,结果为 10*10+9*9+8*8+......+2*2+1*1=385

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

  • A. 582
  • B. 580
  • C. 579
  • D. 581
答案

B

即构造一个 100 节点的二叉树,想要值最小则尽可能形成完全二叉树
1*1+2*2+4*3+8*4+16*5+32*6+37*7=580

T19

(矩阵变幻)有一个奇幻的矩阵,在不停地变幻,其变幻方式为:数字 0 变成矩阵 [0001],数字 1 变成矩阵 [1110]。最初该矩阵只有一个元素 0,变幻 n 次后,矩阵会变成什么样?
例如,矩阵最初为:[0];矩阵变幻 1 次后:[0001];矩阵变幻 2 次后:[0000010100110110]
输入一行一个不超过 10 的正整数 n,输出变幻 n 次后的矩阵,试补全程序
提示:“<<”表示二进制左移运算符,例如 (11)2<<2=(1100)2;而“^”表示二进制异或运算符,它将两个参与运算的数中的每个对应的二进制位一一进行比较,若两个二进制位相同,则运算结果的对应二进制位为 0,反之为 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] = _____(1)_____;
return;
}
int step = 1 << (n - 1);
recursive(_____(2)_____, n - 1, t);
recursive(x, y + step, n - 1, t);
recursive(x + step, y, n - 1, t);
recursive(_____(3)_____, n - 1, !t);
}
int main() {
scanf("%d", &n);
recursive(0, 0, _____(4)_____);
int size = _____(5)_____;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++)
printf("%d", res[i][j]);
puts("");
}
return 0;
}

1. ①处应填

  • A.n % 2
  • B.0
  • C.t
  • D.1
答案

C

res[x][y] 仅有这处赋值,从题意和递归调用时 t 的赋值可知为 t

2. ②处应填

  • A.x - step, y - step
  • B.x, y - step
  • C.x - step, y
  • D.x, y
答案

D

四次递归调用代表一个数扩充为 4 个,x、y 是其坐标,②处为左上,坐标不变

3. ③处应填

  • A.x - step, y - step
  • B.x + step, y + step
  • C.x - step, y
  • D.x, y - step
答案

B

四次递归调用代表一个数扩充为 4 个,x、y 是其坐标,③处为右下,x、y 均增加

4. ④处应填

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

B

第一次调用 recursive 函数,n 是矩阵规模,初始为 n,t 是 0 或 1,初始为 0
第一个空处递归函数返回点是 n==0,每次递归 n-1,第二个空处递归函数每次前三个是 t,则主函数第一次调用是 0

5. ⑤处应填

  • A.1 << (n + 1)
  • B.1 << n
  • C.n + 1
  • D.1 << (n - 1)
答案

B

size 是输出矩阵的边长,2n,位运算是 1 << n

T20

(计数排序)计数排序是一个广泛使用的排序方法。下面的程序使用双关键字计数排序,将 n 对 10000 以内的整数,从小到大排序,试补全程序
例如有三对整数 (3,4)、(2,4)、(3,3),那么排序之后应该是 (2,4)、(3,3)、(3,4)
输入第一行为 n,接下来 n 行,第 i 行有两个数 a[i] 和 b[i],分别表示第 i 对整数的第一关键字和第二关键字
从小到大排序后输出
数据范围:1<n<107;1<a[i],b[i]<104
提示:应先对第二关键字排序,再对第一关键字排序,数组 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;
}

1. ①处应填

  • A.++cnt[i]
  • B.++cnt[b[i]]
  • C.++cnt[a[i] * maxs + b[i]]
  • D.++cnt[a[i]]
答案

B

先对第二关键字进行桶计数

2. ②处应填

  • A.ord[--cnt[a[i]]] = i
  • B.ord[--cnt[b[i]]] = a[i]
  • C.ord[--cnt[a[i]]] = b[i]
  • D.ord[--cnt[b[i]]] = i
答案

D

cnt[b[i]] 表示按第二关键字排序,第 i 个数排第几位,ord[x] 表示第二关键字排名第 x 的数在原序列的下标

3. ③处应填

  • A.++cnt[b[i]]
  • B.++cnt[a[i] * maxs + b[i]]
  • C.++cnt[a[i]]
  • D.++cnt[i]
答案

C

再对第一关键字进行桶计数

4. ④处应填

  • A.res[--cnt[a[ord[i]]]] = ord[i]
  • B.res[--cnt[b[ord[i]]]] = ord[i]
  • C.res[--cnt[b[i]]] = ord[i]
  • D.res[--cnt[a[i]]] = ord[i]
答案

A

统计出最后结果,res[x] 表示 a[] 为第一关键字,b[] 为第二关键字排序第 x 的数对在原序列的下标

5. ⑤处应填

  • A.a[i], b[i]
  • B.a[res[i]], b[res[i]]
  • C.a[ord[res[i]]], b[ord[res[i]]]
  • D.a[res[ord[i]]], b[res[ord[i]]]
答案

B

res[i] 记录第 i 个数在原序列的位置,且 a、b 数组内容必然成对输出,下标必须一致

posted @   RonChen  阅读(135)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示