CSP 2020 第一轮(初赛)模拟解析
一、十进制数
A.
点击查看答案
根据原码补码反码的有关定义可得:
-114 的源码为 :0111 0010
反码为 :1000 1101
故补码为 :1001 1110,
下贴原码补码反码的相关定义:
正数的原码、反码、补码均相同。
原码:用最高位表示符号位,其余位表示数值位的编码称为原码。其中,正数的符号位为 0,负数的符号位为 1。
负数的反码:把原码的符号位保持不变,数值位逐位取反,即可得原码的反码。
负数的补码:在反码的基础上加 1 即得该原码的补码。
此题为简单题,熟记概念即可,不应扣分。
二、以下哪个网站不是 Online Judge(在线程序判题系统)?Online Judge 可以查看算法题目,提交自己编写的程序,然后可以获得评测机反馈的结果。
A. Luogu
点击查看答案
A.Luogu 洛谷是基于网页形式的信息学在线评测系统。同时具有多种社区功能
B.Gitee 又称码云,是基于Git的代码托管网站,约等于Github
C.LeetCode 又名力扣,是一个为全球程序员提供 IT 技术职业化提升的平台,提供了完善的在线判题服务(OJ)、学习工具、社区讨论及模拟面试功能
D.Codeforces 是一家为计算机编程爱好者提供在线评测系统的俄罗斯网站。
以上部分内容来自于百度
此题为简单题,不应扣分。
三、小 A 用字母
A.
点击查看答案
本题可近似理解为进制转换:
故的以下等式:
BYT = 2*26*26 + 25*26 + 20 = 2022
此题为简单题,核心在理解题面,不应扣分。
四、UIM 拍摄了一张照片,其分辨率是
A.8MB
点击查看答案
带入图片内存大小运算公式:
图片所占内存大小 = 图片长度(像素) * 图片宽度(像素) * 一个像素所占内存空间
= 4096 * 2160 * 24 = 212336640 bit = 26542080Byte
= 25920 KB = 25.3125 MB
此题为简单题,理解核心公式,不应扣分。
五、在一个长度为
A.
点击查看答案
通过简单的朴素思路可以将BCD三个选项的算法设计
B 通过冒泡排序或者选择排序的排序规则,第k大值会在第k轮被排入有序序列,进行k轮冒泡或选择排序即可得到结果。
C 这个复杂度的算法非常多样,包括但不限于快速排序直接查找,构建平衡树
D 暴力枚举比大小,亦或插入排序
这时考虑如何设计A项复杂度的算法:(相对有点难度,不过是经典的模型)
1. 首先任选一个树x,将原数组A分为Sa,Sb两个部分,满足Sa中的元素均大于等于x,Sb中元素均小于等于x
若Sa中的元素个数小于k,那么Sb中的第k-|Sa|大的元素即为答案
反之,Sa中第k大的元素的答案
2.按照规则分治递归处理
故平均复杂度可以用递推表达式表示为 T(n) = 2T(n/2) + O(1),即复杂度为 O(n)
此题难度较难,可以允许扣分
六、对于“树”这种数据结构,正确的有:
①一个有
②一个树中的两个顶点之间有且只有一条简单路径
③树中一定存在度数不大于
④树可能存在环
A. ①②④
点击查看答案
①树保证连通性
④根据树的定义树上不存在环
此题为简单题,熟记概念即可,不应扣分。
七、博艾中学进行了一次信息学会考测试,其优、良、及格、不及格的试卷数量分别为
A. 84
点击查看答案
由题目题面的“将一堆数量为 n 的卷子分成两堆,就会产生 n 次分卷子的操作”。
那么可以得到很直观的贪心思维,应该让每一轮产生还继续分的堆的卷子尽量少:
于是得到两个算法,相对平均分成两堆在分开 : 10+13+14+5+13+10+14+5 = 84
从大到小挑出卷子: 10+13+14+5+10+13+5+10+5+5=85
故得到答案
此题为简单题,争取不扣分。
八、一个二叉树的前序遍历是
A. 7
点击查看答案
1.先序遍历
(1)访问根结点;
(2)先序遍历左子树;
(3)先序遍历右子树。
2.中序遍历
(1)中序遍历左子树;
(2)访问根结点;
(3)中序遍历右子树。
3.后序遍历
(1)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根结点。
第一步:还是先求root根节点,根据前序遍历规则我们可知root为前序遍历序列的第一个节点,因此该二叉树的root节点为H。
第二步:求root的左子树和右子树,这点我们还是从中序遍历序列中找出,位于root节点H左侧的B-G为root的左子树,位于H右侧的F-A-E-D-C为右子树。
第三步:求root的左子树的根节点和右子树的根节点。我们可以找到左子树B-G在前遍历序列中的排列顺序为G-B,由于前序遍历最先访问根节点,所以G为左子树的根节点,右子树同理
第四步:我们可以根据上面的步骤找到G的左子树和右子树,以及D的左子树和右子树,然后分别求出左右子树的根节点。以此类推,只要求出根节点及其和,剩下的过程都是递归的,最后我们就可以还原整个二叉树。
一直后序和中序求前序同理
此题为简单题,不应扣分。
九、在 C++ 语言中,如果 a=1 ;b=0 ;c=1 ; 那么以下表达式中为
A. a&&b||b&&c
点击查看答案
A a&&b||b&&c = 0 || 0 = 0
B a+b>c||b = 1 + 0 > 1 || 0 = 0 || 0 = 0
C !(!c&&(!a||b)) = !(!c&&(0||0)) = !(0&&0) = !0 = 1
D a+b+c = 2
十、在一个初始长度为
A.
点击查看答案
每次均插在第二个,即只需要遍历 n 次
此题为简单题,牢记运算优先级,不应扣分。
十一、A 班有
A. 9
点击查看答案
暴力分类讨论计算:以C班选几个人为分类依据得:答案为4+5+5+4 = 18
此题为简单题,牢记运算优先级,不应扣分。
十二、以下哪种排序算法的时间复杂度是
A. 计数排序
点击查看答案
此题为简单题,不应扣分。
十三、已知 rand()
可以生成一个
A. (rand()%(b-a))+a
(rand()%(b-a+1))+a
(rand()%(b-a))+a+1
(rand()%(b-a+1))+a+1
点击查看答案
根据rand函数的定义得:
A:[a,b)
B:[a,b]
C:(a,b]
D:(a,b+1]
此题为简单题,不应扣分。
十四、一个
A. 16
点击查看答案
森林的定义:每个连通分量都是树的图
由定义可得:一棵树也是一个森林
故一个n个点的森林最多只有n-1条边
而n个点的完全图有n * (n-1) / 2
故答案为 21 - 6 = 15
此题为简单题,不应扣分。
十五、2020 年 8 月,第( )届全国青少年信息学奥林匹克竞赛在( )举行?
A. 26,广州
点击查看答案
逆天背诵题,没实践意义。
十六、
#include<iostream>
using namespace std;
#define MAXN 20
int gu[MAXN][MAXN];
int luo(int n, int m) {
if(n <= 1 || m < 2)
return 1;
if(gu[n][m] != -1)
return gu[n][m];
int ans = 0;
for(int i = 0; i < m; i += 2)
ans += luo(n - 1, i);
gu[n][m] = ans;
return ans;
}
int main() {
int n, m;
cin >> n >> m;
for(int i = 0; i < MAXN; i++)
for(int j = 0; j < MAXN; j++)
gu[i][j] = -1;
cout << luo(n, m);
return 0;
}
判断题
1.(1 分)luo 函数中,
A. 正确
2.(1 分)若将第
A. 正确
3.若将第
A. 正确
4.在添加合适的头文件后,将第 19 到 21 行替换为 memset(gu,255,sizeof(gu));
可以起到相同的作用( )
A. 正确
选择题
5.(4 分)若输入数据为 4 8,则输出为( )。
A. 7
6.最坏情况下,此程序的时间复杂度是( )。
A.
点击查看答案
1.通过简易的举反例即可得到结果: n=1,m=1可以运行
核心是m奇偶性对luo函数的执行没有影响,执行影响运算结果。
2.若m为偶数,那么如果更改ans运算过程中会多加一个值luo(n-1,m)
3.根据代码的设计,该函数显然在进行记忆化搜索,其中第8、9、13行就起到记忆化的作用
若删去则luo函数变为普通的深度优先搜索,但这样的更改并不会影响运算结果只会影响运算效率
4.本体重点考察memset函数的底层运算逻辑。memset(void *s, int ch, size_t n);函数将s中当前位置后面的n个字节用 ch 替换并返回 s。
根据函数的功能可以看到memset是以字节为基本单位进行操作的。而int类型有4个字节大大小,且255用二进制表示为1111 1111。
故如调用memset(gu,255,sizeof(gu))则gu函数中的变量会被赋为 1111 1111 1111 1111 1111 1111 1111 1111 即-1
5.列表,将记忆化搜索转为dp进行计算,如下表:
6.因为luo函数进行了记忆化操作实际上复杂度就变为2维的dp,由转移方程得单次转移需要遍历O(m)级别的点
故算法整体复杂度为A
n\m | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 1 | 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 |
3 | 1 | 1 | 1 | 2 | 2 | 4 | 4 | 7 | 7 |
4 | 1 | 1 | 1 | 2 | 2 | 4 | 4 | 8 | 8 |
十七、
#include<bits/stdc++.h>
using namespace std;
int n, m;
int f[101][101];
int F[101][101];
int main() {
scanf("%d%d", &n, &m); // n的值在1到100之间
memset(f, -1, sizeof(f));
for(int i = 1; i <= m; i++) {
int u, v, w; // w的值在0到10000之间
scanf("%d%d%d", &u, &v, &w);
f[u][v] = f[v][u] = w;
}
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(f[i][k] != -1 && f[k][j] != -1)
if(f[i][j] == -1||f[i][j]>f[k][j]+f[i][k])
f[i][j] = f[i][k] + f[k][j];
int ans = 2147483647;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) {
for(int x = 1; x <= n; x++)
for(int y = 1; y <= n; y++)
F[x][y] = f[x][y];
F[i][j] = F[j][i] = 0;
for(int x = 1; x <= n; x++)
for(int y = 1; y <= n; y++)
if(F[x][y]==-1||F[x][y]>F[x][i]+F[i][y])
F[x][y] = F[x][i] + F[i][y];
for(int x = 1; x <= n; x++)
for(int y = 1; y <= n; y++)
if(F[x][y]==-1||F[x][y]>F[x][j]+F[j][y])
F[x][y] = F[x][j] + F[j][y];
int res = 0;
for(int x = 1; x <= n; x++)
for(int y = 1; y < x; y++)
res += F[x][y];
ans = min(res, ans);
}
printf("%d\n", ans);
return 0;
}
判断题
1.(1 分)14 到 16 行,将外层到内层的循环变量依次调整为
A. 正确
2.这个程序的时间复杂度和
A. 正确
3.20 行的
A. 正确
4.若将第 27 到 30 行的部分和 31 到 34 行的两个部分互换,程序的运行的结果不变。( )
A. 正确
选择题
5.若输入数据为 4 5/1 2 3/1 3 6/2 3 4/2 4 7/3 4 2(其中“/”为换行符),则输出为( )。
A. 14
6.这个程序使用了( )算法。
A. Floyd
点击查看答案
1.若将Floyd的内外层变量调换则可能会造成Floyd所求做短路可能错误
2.算法的复杂度表达为O(n^4+m),此时算法复杂的和m与n^4的级数有关
3.假设是链式的形态,只计算中间节点,节点长度ans就有最多 : 50 * 49 * 10000 > 1e7
4.i,j 从1到n的所有组合都被分类到故无需考虑i,j 的具体顺序。
5.根据Floyd处理将最短路可得下表
n\m | 1 | 2 | 3 | 4 |
---|---|---|---|---|
1 | -1 | 3 | 6 | 8 |
2 | 3 | -1 | 4 | 6 |
3 | 6 | 4 | -2 | 2 |
4 | 8 | 6 | 2 | -1 |
本代码的意思的;添加一条从i到j的花费为0的路径再求最短路之和:
那么若将1-4的边改为0.最短路和就变为了 3+2+0+2++4 = 14
6.很显然存在Floyd的代码段
十八、
#include<bits/stdc++.h>
using namespace std;
#define MOD 19260817
#define MAXN 1005
long long A[MAXN][MAXN] = {0}, sum[MAXN][MAXN] = {0};
int n, m, q;
int main() {
A[1][1] = A[1][0] = 1;
for(int i = 2; i <= 1000; i++) {
A[i][0] = 1;
for(int j = 1; j <= i; j++)
A[i][j] = (A[i - 1][j] + A[i - 1][j - 1]) % MOD;
}
for(int i = 1; i <= 1000; i++)
for(int j = 1; j <= 1000; j++)
sum[i][j] = (sum[i - 1][j] + sum[i][j - 1]
- sum[i - 1][j - 1] + A[i][j] + MOD) % MOD;
int q;
cin >> q;
while(q--) {
int n, m;
cin >> n >> m;
cout << sum[n][m] << endl;
}
return 0;
}
判断题
1.(1 分)当
A. 正确
2.当
A. 正确
3.sum[i][j] 的值(
A. 正确
4.若将第 12 行改为 A[i][j]=(A[i-1][j]+A[i-1][j-1]+MOD)%MOD;,程序的运行的结果不变。( )
A. 正确
选择题
5.(4 分)A[i][j](
A. 126
6.若输入数据为 1/5 3(其中“/”为换行符),则输出为( )。
A. 10
点击查看答案
1.根据A的经典转移方程可以的到A[i][j]就是从i个元素中选j个的组合数,根据组合数的定义可以得到若i<j则A[i][j] = 0,若i=j则A[i][j] = 1
2.跟据上述的分析,A[i][j]是从i个元素中选j个的组合数
3.等存在模数的时候就可能以为取模的导致实际数值sum[i][j] < sum[i][j]
4.MOD = 19260817, 故3*MOD = 57782451 < INT_MAX,不会越界
5.因为 i,j 数值较小不涉及取模, 按照组合数的性质定理那么A[10][5]最大,最大值为252
6.求二维前缀和sum数组如下:
n\m | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 |
2 | 3 | 4 | 4 | 4 | 4 |
3 | 6 | 10 | 11 | 11 | 11 |
4 | 10 | 20 | 25 | 26 | 26 |
5 | 15 | 35 | 50 | 56 | 57 |
十九、
(封禁 xxs)现有
输入第一行是一个不超过
输出一行,一个整数表示答案。
#include <cstdio>
using namespace std;
#define MAXN 300005
int n, ans = 0, a[MAXN], in[MAXN] = {0};
bool vis[MAXN] = {0};
void dfs(int cur, int w) {
if(vis[cur])
return;
vis[cur] = true;
if(w == 1) ans++;
①
if(②)
dfs(a[cur], ③);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
in[a[i]]++;
}
for(int i = 1; i <= n; i++)
if(!in[i]) ④;
for(int i = 1; i <= n; i++)
if(⑤) dfs(i, 0);
printf("%d\n", ans);
return 0;
}
1.①处应填( )
A. a[cur]=cur;
2.②处应填( )
A. in[a[cur]]!=0||w == 1
3.③处应填( )
A. 0
4.④处应填( )
A. dfs(i,1)
5.⑤处应填( )
A. !in[i]
点击查看答案
分析题目中哪些条件下处理简单:
首先, 若只有一条链则交替封禁xxs就可以简单实现
而若产生两条链交叉,则可以在交叉点分成两条链式结构.
而复杂问题是会出现环状图形.当产生环之后就需要考虑破环成链从某一结点入手(考虑不举报这个人就可以直接破环)
此时核心的分类已经讨论完成了,那么只需要按照思路思考即可:
首先主函数内显然21-22,与23-24在做分类讨论: 圈4就显然是的dfs(i,1)
而圈5的含义应表示没有考虑过的点,而代码用vis数组记录是否搜索过所以应为!vis[i]
圈2的就是考虑什么情况可以搜索即上文分析的(非环且不交叉)或(环上不举报的点), 转换成代码含义即!in[a[cur]] or w == 1
同时根据交叉举报的原则圈3 w^=1 等价于 w = 1-w
圈1就简单得到要更改图上信息即 in[cur]--
二十、
(烧作业)某课作业布置了
输入第一行是整数
输出一行,若干个整数表示答案。如果有多个
#include <cstdio>
#include <cmath>
#define min(a,b) (a<b?a:b)
#define MAXN 100002
using namespace std;
int n, k[MAXN], cnt = 0;
int s[MAXN], minScore, sum;
double maxAverage = 0, nowAverage;
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &s[i]);
minScore = s[n];
①;
for(int i = n - 1; i >= 2; i--) {
minScore = min(minScore, s[i]);
②;
nowAverage = ③;
if(nowAverage > maxAverage) {
④
maxAverage = nowAverage;
} else if(fabs(nowAverage - maxAverage) < 1e-6)
⑤;
}
for(int i = cnt; i >= 1; i--)
printf("%d\n", k[i]);
return 0;
}
1.①处应填( )
A. sum=n
2.②处应填( )
A. sum=maxAverage*(n-i)
3.③处应填( )
A. (double)(sum+minScore)/(n-i)
4.④处应填( )
A. k[++cnt]=i;
5.⑤处应填( )
A. k[cnt++]=i;
点击查看答案
简单总结目标是:求后缀平均数最大
从后向前以此计算,需要处理的就是后缀和,后缀最小值 即sum,minScore
根据第15行的循环起点i = n-1 那么sum应初始为最后一个数即 s[n]
而后缀和sum的处理相对简单,无需具体讲解
圈3的题目 C向 转int 会导致结果精度不准确影响答案, 所以要用double类型
圈4要清空重新统计答案,但由于k[cnt]的写法,cnt不应清空. 且考虑是清空前k个作业,故不应包括i
圈5应使用 ++cnt 去统计数组位置, 填入数字原则同上
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话