2023CSP-S第一轮提高组初赛真题解析

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

1. 在Linux系统终端中,以下哪个命令用于创建一个新的目录?(     )

A. newdir

B. mkdir

C. create

D. mkfolder

答案:B,计算机基础,Linux的基础操作知识。

2. 0,1,2,3,4中选取4个数字,能组成(     )个不同四位数。(注:最小的四位数是1000,最大的四位数是9999。)

A. 96

B. 18

C. 120

D. 84

答案:A,组合计数,分步,千位有4种选择,百位4种,十位3种,个位2种,乘法原理,4*4*3*2=96。

3. 假设n是图的顶点的个数,m是图的边的个数,为求解某一问题有下面四种不同时间复杂度的算法。对于m=θ(n)的稀疏图而言,下面的四个选项,哪一项的渐近时间复杂度最小。

A. O(m√logn·loglogn ) 

B. O(n²+m)

C. O(n²/logm+mlogn)

D. O(m+nlogn)

答案:A,图论,m和n同一级别,可以把所有的m换成n来比较,loglogn<√logn,所以A<D<C<B。

4. 假设有n根柱子,需要按照以下规则依次放置编号为1、2、3、...的圆环:每根柱子的底部固定,顶部可以放入圆环;每次从柱子顶部放入圆环时,需要保证任何两个相邻圆环的编号之和是一个完全平方数。请计算当有4根柱子时,最多可以放置(     )个圆环

A. 7

B. 9

C. 11

D. 5

答案:C,模拟整个过程,我们发现,每次放圆环都只有一个选择,假设柱子为ABCD,则A1 B2 C3 D4 D5 C6 B7 A8 B9 C10 D11。

5. 以下对数据结构的表述不恰当的一项是(     )

A. 队列是一种先进先出(FIFO)的线性结构

B. 哈夫曼树的构造过程主要是为了实现图的深度优先搜索

C. 散列表是一种通过散列函数将关键字映射到存储位置的数据结构

D. 二叉树是一种每个结点最多有两个子结点的树结构

答案:B,数据结构,哈夫曼树跟DFS没有关联。构造哈夫曼树是一个贪心的过程,可以用来编码压缩。

6. 以下连通无向图中,(     )一定可以用不超过两种颜色进行染色

A. 完全三叉树

B. 平面图

C. 边双连通图

D.欧拉图

答案:A,图论,染色问题是同一条边的两个点用不用的颜色。树是一种二分图(两种颜色即可),或者可以试想一下每一层用不同的颜色。

7. 最长公共子序列长度常常用来衡量两个序列的相似度。其定义如下:给定两个序列X={×1,×2,X3,…,xm}和Y={y1,y2,y3,…,yn},最长公共子序列(LCS)问题的目标是找到一个最长的新序列Z={z1,z2,z3,…,zk},使得序列Z既是序列X的子序列,又是序列Y的子序列,且序列Z的长度k在满足上述条件的序列里是最大的。(注:序列A是序列B的子序列,当且仅当在保持序列B元素顺序的情况下,从序列B中删除若干个元素,可以使得剩余的元素构成序列A。)则序列“ABCAAAABA”和“ABABCBABA”的最长公共子序列长度为(     )

A. 4

B. 5

C. 6

D. 7

答案:C,动态规划,可以肉眼来看,先匹配头尾的AB和ABA,长度为5,剩下CAAA和ABCB只有一个可取。

8. 一位玩家正在玩一个特殊的掷骰子的游戏,游戏要求连续掷两次骰子,收益规则如下:玩家第一次掷出x点,得到2x元;第二次掷出y点,当y=x时玩家会失去之前得到的2x元,而当y≠x时,玩家能保住第一次获得的2x元。上述x,y∈{1,2,3,4,5,6}。例如:玩家第一次掷出3点得到6元后,但第二次再次掷出3点,会失去之前得到的6元,玩家最终收益为0元;如果玩家第一次掷出3点、第二次掷出4点,则最终收益是6元。假设骰子掷出任意一点的概率均为1/6,玩家连续掷两次骰子后,所有可能情形下收益的平均值是多少?(     )

A. 7元

B. 35/6

C. 16/3

D. 19/3

答案:B,概率和期望,假设第一次是a,则5/6的可能性获得2a,1/6的可能性获得0,期望收益是2a*5/6=5a/3,而第一次的期望(1+2+3+4+5+6)/6=7/2,所以5/3*7/2=35/6。

9. 假设我们有以下的C++代码:

图片

请问,res的值是什么?(     )

提示:在C++中,逻辑运算的优先级从高到低依次为:逻辑非(!)、逻辑与(&&)、逻辑或(||)。位运算的优先级从高到低依次为:位非(~)、位与(&)、位异或(^)、位或(I)。同时,双目位运算的优先级高于双目逻辑运算;逻辑非和位非优先级相同,且高于所有双目运算符。

A. true

B. false

C. 1

D. 0

答案:A,运算,题目提示了优先级, a&b=1,c^b=7,a|c=5,7&&5=true,1||true=true。

10. 假设快速排序算法的输入是一个长度为n的已排序数组,且该快速排序算法在分治过程总是选择第一个元素作为基准元素。以下哪个选项描述的是在这种情况下的快速排序行为?(     )

A. 快速排序对于此类输入的表现最好,因为数组已经排序

B. 快速排序对于此类输入的时间复杂度是0(nlogn)

C. 快速排序对于此类输入的时间复杂度是0(n²)

D. 快速排序无法对此类数组进行排序,因为数组已经排序

答案:C,排序,快速排序越有序越慢,因为没法均分为两组,而是分成了1和n-1。

11. 以下哪个命令,能将一个名为“main.cpp”的C++源文件,编译并生成一个名为“main”的可执行文件?(     )

A. g++-o main main.cpp

B. g++-o main.cpp main

C. g++ main -o main.cpp

D. g++ main.cpp -o main.cpp

答案:B,-o后面必须接可执行文件的名字。

12. 在图论中,树的重心是树上的一个结点,以该结点为根时,使得其所有的子树中结点数最多的子树的结点数量最少。一棵树可能有多个中心。请问下面哪种树一定只有一个重心?(     )

A. 4个结点的树

B. 6个结点的树

C. 7个结点的树

D. 8个结点的树

答案:C,图论和树,重心可能有两个,偶数个结点的树我们可以构造成一条链,当中的两个结点都是重心。排除A B D。

13. 如图是一张包含6个顶点的有向图,但顶点间不存在拓扑序。如果要删除其中一条边,使这6个顶点能进行拓扑排序,请问总共有(     )条边可以作为候选的被删除边。

图片

A. 1

B. 2

C. 3

D. 4

答案:C,拓扑排序,不能有环,所以1、3、4三个点之间的边任意去掉一条就可以进行拓扑排序。

14.

图片

其中xi

属于{0,1,2,3,...,15},对于给定自然数n0,存在序列n0,n1,...,nm,对于1<=i<=m都有 ni=f(ni-1)且nm=nm-1,则称nm为n0关于f的不动点,问在100(16)到1A0(16)中,关于f的不动点是9的自然数个数是(     )。

A. 10

B. 11

C. 12

D. 13

答案:B,进制,n可以写成16进制,xk..x1x0,f(n)实际上各个位的和,也就是在固定范围内找各位数字和为9的数或者几次变换后数字和为9的数。

108,117,126,135,144,153,162,171,180,(9个),100(16)-1A0(16)范围内数字和最大为25,仅当数字和是24,即18(16)时,序列的下一个数能变为9,而数字和24的数只有18F和19E两个,所以加起来一共11个。

15. 现在用如下代码来计算xn,其时间复杂度为:

图片

A. O(n)

B. O(1)

C. O(logn)

D. O(nlogn)

答案:A,可以画一下递归的树型结构,可以发现是一颗满二叉树,节点数是2^logn=n,这个写法跟正常的快速幂的不同之处在于quick_power调用了两次。

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

图片

假设输入的x是不超过65535的自然数,完成下面的判断题和单选题。

判断题:

16. 当输入非零时,输出一定不为零。(     )

答案:T,左移+异或,最右边的1肯定不会消失;右移+异或,最左边的1肯定不会消失,所以两步运算以后都不会出现0。

17. (2分)将f函数的输入参数的类型改为unsigned int,程序的输出不变。(     )

答案:F,unsigned int是32位,假设输入65535,左移6位,16个1+6个0,异或操作后是6个1+10个0+6个1,右移8位变成6个1+8个0,异或后8个1+2个0+6个1,输出变了。

18. 当输入为“65535”时,输出为“63”。(     )

答案:T,65535是16个1,左移6位,是10个1+6个0,异或操作后是6个1,右移8位变成0,所以输出是6个1,也就是2^6-1=63。

19. 当输入为“1”时,输出为“64”。(     )

答案:F,1,左移6位,1000000,异或操作后1000001,右移8位变成0,所以输出是1000001,也就是2^6+1=65。

单选题:

20. 当输入为“512”时,输出为(     )。

A.“33280”

B.“33410”

C.“33106”

D.“33346”

答案:B,1000000000,左移6位,1个1+15个0,异或后是1个1+5个0+1个1+9个0,右移8位,1个1+5个0+1个1+1个0,异或后1个1+5个0+1个1+1个0+1个1+5个0+1个1+1个0。

21. 当输入为“64”时,执行完第5行后x的值为(     )。

A.“8256”

B.“4130”

C.“4128”

D.“4160”

答案:D,1000000,左移6位,1个1+12个0,异或后是1个1+5个0+1个1+6个0=4096+64=4160。

阅读程序题(1)整体解析:

位运算,注意:无符号整数的右移,左边的空位补0;计算要仔细。

图片

假设输入的n是不超过1000000的自然数,完成下面的判断题和单选题。

判断题:

22. 将第15行删去,输出不变。(     )

答案:F,删除以后,g[i]就不是满足最小质因数的最高幂次的因数了。(简单)

23. 当输入为“10”时,输出的第一行大于第二行。(     )

答案:F,第一行是87,第二行是87,从这道题目,暗示了solve2和solve1解决的是同一个问题。实际上枚举了因数i,而i在1-n的数中贡献了n/i次。其实也是在计算1-n的约数和的和。(简单)

24. (2分)当输入为“1000”时,输出的第一行与第二行相等。(     )

答案:T,按上题的理解,相同。(难)

单选题:

25. solve1(n)的时间复杂度为(     )

A. O(nlog²n) 

B. (O(n))

C. (O(nlogn))

D. (O(nloglogn)

答案:D,埃式筛法的复杂度。(难)

26. solve(2)的时间复杂度为(     )

A. O(n²)

B. O(n)

C. O(nlogn)

D. O(nloglogn)

答案:B,显然。(简单)

27. 输入为"5"时,输出的第二行为(     )

A.“20”

B.“21”

C.“22”

D.“23”

答案:B,5+4+3+4+5=21。(简单)

阅读程序题(2)整体解析:

solve2可以比较简单的模拟,但是一时看不出来含义,solve1的算法类似筛法,p表示是否质数,k是i的幂次数组,f存的是最小质因数,g存的是满足最小质因数的最高幂次的因数。

f[i]= f[i / g[i]]*(g[i]* f[i]- 1)/(f[i]- 1); 是最难理解的一句。

首先 f[i/g[i]],因为i/g[i]<i,所以这个f[i/g[i]] 已经是经过计算的新的值。类似动态规划中数组的复用。

(g[i]*f[i]-1)/(f[i]-1),有点像等比数列求和公式,实际上求的是1,f[i],f[i]*f[i],...,g[i]这个数列的和。

如果能联想到求一个数的约数和的公式,可以理解完整的一行,实际上是在求i的所有约数和。sum是1-n的约数和的和。

图片

假设输入总是合法的且|a[i]|≤108、n≤10000和1≤k≤n(n-1)/2,完成下面的判断题和选择题。

判断题:

28. 将第24行的“m”改为“m-1”,输出有可能不变,而剩下情况为少1。(     )

答案:T,二分的右边界可能会变成比满足条件的最小值小1的那个,也有可能这行没有执行到,一直g=m+1,则输出不变。

29. 将第22行的“g+(h-g)/2”改为“(h+g)>>1”,输出不变。(     )

答案:T,h的最大值是2*10^8,换一个方式计算mid不会越界。

30. 当输入为“5 7 2 -4 5 1 -3”,输出为“5”。(     )

答案:T,排序后是-4 -3 1 2 5,差值不超过4的数对只有5对,差值不超过5的数对有7对,所以5是最小满足条件的值。

单选题:

31. 设a数组中最大值减最小值加1为A,则f函数的时间复杂度为(     )

A. O(nlogA)

B. O(n²logA)

C. O(nlog(nA))

D. O(nlogn)

答案:C,sort的复杂度O(nlogn),二分部分的复杂度O(nlogA),加起来就是nlogn+nlogA=nlog(nA),这里A和n的数量级不清楚,不能简化。

32. 将第10行中的“>”替换为“>=”,那么原输出与现输出的大小关系为(     )

A. 一定小于

B. 一定小于等于且不一定小于

C. 一定大于等于且不一定大于

D. 以上三种情况都不对

答案:B,变成了差值小于x的数对个数,相当于判断条件变严格了,答案可能会变大或者不变。

33. 当输入为“5 8 2 -5 3 8 -12”时,输出为(     )

A.“13”

B.“14”

C.“8”

D.“15”

答案:B,排序后是-12 -5 2 3 8,差值不超过14的数对是8,差值不超过13的数对是7。

阅读程序题(3)整体解析:

读f函数可知,f0中的a数组是从小到大排序的,a[j]<a[i]-m,j是小于a[i]-m的最后一个位置(或者0),所以s是计算序列a中差值不超过m的数对的个数。

f0判断满足这个条件的数对个数是否>=k。本题需要看懂题目才方便做题。

f函数是一个二分查找,g=0,h=a.back()-a[0],分别是条件最紧和条件最宽松,返回值是最小的x,满足a中差值不超过x的数对个数>=k。

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

1、(第k小路径)给定一张n个点m条边的有向无环图,顶点编号从0到n-1。对于一条路径,我们定义"路径序列"为该路径从起点出发依次经过的顶点编号构成的序列。

求所有至少包含一个点的简单路径中,“路径序列"字典序第k小的路径。保证存在至少k条路径,上述参数满足1≤n,m≤105和1≤k≤1018。

在程序中,我们求出从每个点出发的路径数量。超过1018的数都用1018表示。然后我们根据k的值和每个顶点的路径数量,确定路径的起点,然后可以类似地依次求出路径中的每个点。

试补全程序:

图片

34. ①处应填(     )

A. k >= f[u]

B. k <= f[u]

C. k >f[u]

D. k< f[u]

答案:B,next函数是在cand队列中查找第k条在哪个结点为起点的路径中,所以如果k<=f[u],说明第k小就在u为起点的路径中,否则k-=f[u],找下一个结点。

35. ②处应填(     )

A. deg[v]== 1

B. deg[v]== o

C. deg[v]>1

D. deg[v]>o

答案:A,入度为0的点入队列,--deg[v]在入队列的后面执行,所以这里判断deg[v]==1;题目保证了是DAG,所以整个队列中一定会有n个结点。

36. ③处应填(     )

A. std::min(f[u]+ f[v],LIM)

B. std::min(f[u]+ f[v]+ 1,LIM)

C. std::min(f[u]* f[v],LIM)

D. std::min(f[u]*(f[v]+ 1),LIM)

答案:A,动态规划,计算u为起点的路径树,f[u]=1是只有自身的一条路,枚举所有子结点的路径数,累加。先把Q逆序是因为要拓扑序靠前的结点计算依赖拓扑序靠后的结点。

37. ④处应填(     )

A. u!=-1

B. !E[u].empty()

C. k >0

D. k >1

答案:D,next函数执行后我们知道了第k小的路径在u开头的路径中,当k==1时,这条路径就只有u一个结点,如果k>1,则需要从u的子结点中继续找。

38. ⑤处应填(     )

A. k += f[u]

B. k -= f[u]

C. --k

D. ++k

答案:C,--k表示减去u为唯一结点的那条路径。后两空相对比较难。

完善程序题1 整体解析:

拓扑排序+动态规划,基本思路是先拓扑排序,然后按从后往前的顺序计算每个结点为起点的路径数,然后按编号排序找第k小路径的起点。

2、(最大值之和)给定整数序列ao,a₁,a₂……an,求该序列所有非空连续子序列的最大值之和。上述参数满足1≤n≤105和1≤ai≤108。

一个序列的非空连续子序列可以用两个下标I和r(其中0≤l≤r≤n)表示,对应的序列为al,al+1,al+2,……ar。两个非空连续子序列不同,当且仅当下标不同。

例如,当原序列为[1,2,1,2] 时,要计算子序列[1],[2],[1],[2],[1,2],[2,1],[1,2],[1,2,1],[2,1,2],[1,2,1,2]的最大值之和,答案为18。注意[1,1]和[2,2]虽然是原序列的子序列,但不是连续子序列,所以不应该被计算。

另外,注意其中有一些值相同的子序列,但由于他们在原序列中的下标不同,属于不同的非空连续子序列,所以会被分别计算。解决该问题有许多算法,以下程序使用分治算法,时间复杂度O(nlogn).

尝试补全程序:

图片

39. ①处应填(     )

A. pre[i]=std::max(pre[i-1],a[i-1])

B. pre[i + 1]= std::max(pre[i],pre[i +1])

C. pre[i]= std::max(pre[i - 1],a[i])

D. pre[i]= std::max(pre[i],pre[i - 1])

答案:D,std::vectorpre(a + mid, a+r); 复制从a[mid]到a[r-1]的数组。然后计算这个数组的前缀最大值,即pre[i]是从0到i的数组的最大值。

40. ②处应填(     )

A. a[j]< max

B. a[j]< a[i]

C. pre[j - mid]< max

D. pre[j - mid]> max

答案:B,找最大值在前半段还是后半段的分界点,比较容易混淆的是C选项,因为此时max还没有更新,所以不能让a[j]或pre[j-mid]跟max来比,只能跟a[i]来比。

41. ③处应填(     )

A. (long long)(j - mid)* max

B. (long long)(j - mid)*(i - 1)* max

C. sum[j - mid]

D. sum[j - mid]*(i - 1)

答案:A,i为起点,终点在后半段, 且最大值在前半段的个数是(j-mid)个,此时最大值都是max。

42. ④处应填(     )

A. (long long)(r - j)* max

B. (long long)(r - j)*(mid - i)* max

C. sum[r - mid]- sum[j - mid]

D. (sum[r - mid]- sum[j - mid])*(mid - i)

答案:C,i为起点,终点在后半段,且最大值在后半段的情况,最大值的和通过sum前缀和数组计算。

43. ⑤处应填(     )

A. solve(0, n)

B. solve(0, n - 1)

C. solve(1,n)

D. solve(1, n - 1)

答案:A,因为line 12-14行,可以看到二分的结束条件是l+1==r,而且此时取l的值,也就是说[l,r),左闭右开的区间。

完善程序题2 整体解析:

分治算法,分为三部分来计算,1) 起点终点都在前半段;2) 都在后半段;3) 起点在前半段、终点在后半段。前两部分递归解决,难点在于第三部分。预处理后半段的两个数组,pre数组表示前缀数组的最大值(pre数组一定是单调不下降的),sum数组是pre数组前缀和。然后用双指针,前半段从后往前,维护最大值,后半段从前往后。

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值