当前位置: 首页 > news >正文

2023年12月GESP5级C++真题解析,包括选择判断和编程

一、选择题(每道题2分,共30分)

1、下面C++代码用于求斐波那契数列,该数列第1 、2项为1,以后各项均是 前两项之和。下面有关说法错误的是( )

A. fiboA( ) ⽤递归⽅式,fiboB() 循环⽅式

B. fiboA( ) 更加符合斐波那契数列的数学定义,直观易于理解,⽽fiboB() 需 要将数学定义转换为计算机程序实现

C. fiboA( ) 不仅仅更加符合数学定义,直观易于理解,且因代码量较少执⾏ 效率更⾼

D. fiboB( ) 虽然代码量有所增加,但其执⾏效率更⾼

答案:C

解析:A错误,因为fiboA在函数内部自己调用自己是递归,fiboB没有递归还写了for循环,是循环,说法正确,但要选的是错误的。

B错误,因为fiboA确实容易理解,fiboB体现了递推的思想,需要一定计算机基础的人才能看懂。

C正确,fiboA因为没有使用桶记录每个fiboA(i)的值,导致时间复杂度为O(2^n),而fiboB只需要O(n)的时间,fiboA更慢,说法错误,题目要选错误的,故选C

D错误,根据对C选项的分析,fiboB更快,该说法正确,不能选。

2、下⾯C++代码以递归⽅式实现合并排序 ,并假设 merge(intT[],intR[],ints,int m, int t) 函数将有序(同样排序规则) 的T[s..m]和T[m+1..t]归并到R[s..t]中 。 横线处应填上代码是( )。

A. mergeSort(SList, T2, s, m,len), mergeSort(SList, T2, m,t,len)

B. mergeSort(SList, T2, s, m-1,len), mergeSort(SList, T2, m+1,t,len)

C. mergeSort(SList, T2, s, m,len), mergeSort(SList, T2, m+1,t,len)

D. mergeSort(SList, T2, s, m-1,len), mergeSort(SList, T2, m-1,t,len)

答案:C

解析:很明显这是一个归并排序的左闭右闭写法(每个区间都包含左端点和右端点),因此要递归排序左边和右边,而中间的m是分界点,左边的最后一个元素是他,右边的第一个元素的上一个是他,因此左边要写 mergeSort(SList,T2,s,m,len),即s~m,右边要写mergeSort(SList,T2,m+1,t,len);即m+1~t,故选C

3、阅读下⾯的C++代码 ,执⾏后其输出是()

A. 1->120<===>2->120

B. 1->120<===>1->120

C. 1->120<===>1->2->3->4->5->120

D. 1->120<===>2->3->4->5->6->120

答案:D

解析:fracA通过循环求阶乘(1~n的乘积叫n的阶乘),stepCount只会增加1次,因此先输出1->,然后输出结果120,接着是分隔符。

22行结束后输出:1->120<===>

现在fracB通过递归求阶乘,stepCount没有初始化,因此还是1,从1开始,每调用一次就+1并输出,而fracB(5)会调用5次,所以输出2->3->4->5->6->,最后结果120

最终输出:1->120<===>2->3->4->5->6->120,选D

4、下⾯的C++⽤于对lstA 排序,使得偶数在前奇数在后 ,横线处应填⼊( )。

A. isEven(lstA[j]) && !isEven(lstA[j+1])

B. !isEven(lstA[j]) && isEven(lstA[j+1])

C. lstA[j] > lstA[j+1]

D. lstA[j] < lstA[j+1]

好你个GESP,居然把我选项顺序写反了!我说怎么感觉官方答案不对劲!居然解析都写反了!PDF不可信

(PDF链接)https://gesp.ccf.org.cn/101/attach/1594750635343904.pdf

A. !isEven(lstA[j]) && isEven(lstA[j+1])

B. isEven(lstA[j]) && !isEven(lstA[j+1])

C. lstA[j] > lstA[j+1]

D. lstA[j] < lstA[j+1]

答案:A

解析:这是冒泡排序,交换原则是前后顺序不对就交换。

要求前偶后奇,那么出现前奇后偶的情况就交换。

!isEven(lstA[j])表示前面是奇数,isEven(lstA[j+1])表示后面是偶数,所以应填!isEven(lstA[j]) && isEven(lstA[j+1]),故选A。

5、下⾯的C++代码⽤于将字符串保存到带头节点的双向链表中,并对重复的串 计数,然后将最新访问的串的节点放在链头便于查找。横线处应填⼊代码是( )

A. if(pHead) {p->next = pHead->next, pHead->next->prev = p;}

B. if(pHead->next) {p->next = pHead->next, pHead->next->prev = p;}

C. p->next =pHead->next, pHead->next->prev = p;

D. 触发异常 ,不能对空指针进⾏操作。

答案:B

解析:都把元素插到链表头部了,那真正头节点不就是pHead->next了吗,此时只需判断pHead->next是否为空就行了,这时候才能插入,因此选B

6、有关下⾯C++代码说法正确的是( )。

A. 如果 x ⼩于10, rc 值也不会超过20

B. foo 可能⽆限递归

C. foo 可以求出 x 和 y 的最⼤公共质因⼦

D. foo 能够求出 x 和 y 的最⼩公倍数

答案:A

解析:本C++代码用辗转相除法求最大公因数

A是正确的,x<10时最大为9,此时y如果<10,则rc不可能超过20,如果y>=10,就会让x和y的位置对调,在递归一次,x回到原来的位置上了,y因为取模x导致<x,这下rc不可能超过20了。

B错误,foo不可能无限递归,即便y为负数。

C错误,辗转相除法求的是最大公因数。

D错误,辗转相除法求的是最大公因数。

故选A。

7、下⾯的C++代码实现对list的快速排序 ,有关说法 ,错误的是( )。

好家伙,这小代码打的,19~21行能打两次,真服了。

A. qSort(less) + qSort(greater) + (vector)pivot

B. (vector)pivot + (qSort(less) + qSort(greater))

C. (qSort(less) + (vector)pivot + qSort(greater))

D. qSort(less) + pivot + qSort(greater)

答案:C

解析:本代码对vector类进行了运算符重载,+号的意义是合并两个vector,快速排序的思想是通过基准将数组分成两部分,一半比基准小(相等),一半严格比基准大,递归两部分,本代码把小于等于和大于基准的两部分设好了less和greater数组,最后就是返回qsort(less)+vector(pivot)+qsort(greater),代表递归左边的结果、中间元素、递归右边的结果合并后的数组,代表排序结果,故选C

8、下⾯C++代码中的 isPrimeA() 和 isPrimeB() 都⽤于判断参数N是否素数 , 有关其时间复杂度的正确说 法是( )。

A. isPrimeA( ) 的最坏时间复杂度是 0(n/2),isPrimeB( ) 的最坏时间复杂度是 O(logN),isPrimeA() 优于 isPrimeB()

B. isPrimeA() 的最坏时间复杂度是0(n/2 ),isPrimeB( ) 的最坏时间复杂度是 O(N^1/2 ),isPrimeB() 绝⼤多数情况下优于 isPrimeA()

C. isPrimeA() 的最坏时间复杂度是0(N^1/2),isPrimeB( ) 的最坏时间复杂度是 O(N),isPrimeA( ) 优于 isPrimeB( ) 

D. isPrimeA() 的最坏时间复杂度是0(logN) ,isPrimeB() 的最坏时间复杂度 是O(N),isPrimeA() 优于 isPrimeB()

答案:B

解析:O(n/2)是不标准的,但不代表错误,他等价于O(n)。

isPrimeA的时间效率为O(n),因为i从2加到了n/2,isPrimeB的效率为O(n^1/2),因为他只枚举了2~根号n。故选B。

9、下⾯C++代码⽤于有序 list 的⼆分查找 ,有关说法错误的是( )。

A. 代码采⽤⼆分法实现有序 list 的查找

B. 代码采⽤分治算法实现有序 list 的查找

C. 代码采⽤递归⽅式实现有序 list 的查找

D. 代码采⽤动态规划算法实现有序 list 的查找

答案:D

解析:A错误,代码确实是二分,但题目要找错误的说法;

B错误,代码确实在分治,只不过每次递归只调用一次自身罢了;

C错误,代码确实在递归,因为函数_binarySearch自己调用了自己;

D正确,该代码与动态规划没有任何关系。

10、在上题的_binarySearch算法中,如果lst中有N个元素,其时间复杂度是( )

A. O(N)

B. O(logN)

C. O(NlogN)

D. O(N2)

答案:B

解析:二分查找的时间复杂度是O(logn)

11、下⾯的C++代码使⽤数组模拟整数加法,可以处理超出⼤整数范围的加法运 算。横线处应填⼊代码是 () 。

A. c.push_back(t % 10), t = t % 10;

B. c.push_back(t / 10), t = t % 10;

C. c.push_back(t / 10), t = t / 10;

D. c.push_back(t % 10), t = t / 10;

答案:D

解析:结果数组每次只能加入一个位,因此t(进位+两个数的和)的个位要写在结果上,t的个位要去掉,获取个位的代码是t%10,去掉个位保留十位的代码是t/10,因此横线应填c.push_back(t%10),t=t/10;选D。

12、有关下⾯C++代码的说法正确的是( )。

A. 上述代码构成单向链表

B. 上述代码构成双向链表

C. 上述代码构成循环链表

D. 上述代码构成指针链表

答案:B

解析:首先用构造函数创建一个元素10,然后在后面每创建一个元素就将他的前驱指向前面最后一个元素,因此上述代码构成双向链表。

13、通讯卫星在通信⽹络系统中主要起到() 的作⽤ 。

A. 信息过滤

B. 信号中继

C. 避免攻击

D. 数据加密

答案:B

解析:通信卫星可以转发无线电信号,实现通信地球站间或地球站与航天器间的无线电通信,因此具有信号中继作用。选B。

14、⼩杨想编写⼀个判断任意输⼊的整数N是否为素数的程序 ,下⾯哪个⽅法 不合适? ( )

A. 埃⽒筛法

B. 线性筛法

C. ⼆分答案

D. 枚举法

答案:C

解析:埃氏筛法和线性筛法可以找出N以内的素数,判断包不包含N即可;枚举法可以枚举<=根号n的数,通过因数关系判断是否质数;二分答案有点多余。

15、下⾯的排序算法都要处理多趟数据 ,哪种排序算法不能保证在下⼀趟处理 时从待处理数据中选出最⼤或最 ⼩的数据? ( )

A. 选择排序

B. 快速排序

C. 堆排序

D. 冒泡排序

答案:B

解析:选择排序选出最小元素并交换,堆排序选出最大元素放到堆尾,冒泡排序把最大元素冒泡到最后,但快速排序是选出基准,一半大一半小,不能保证选出最大最小,选B

二、判断题(每道题2分,共20分)

1、归并排序的时间复杂度是O(NlogN) 。

答案:正确

解析:归并排序的平均时间复杂度是O(nlogn),另见:数据结构:排序算法之归并排序Merge Sort-CSDN博客

2、⼩杨在⽣⽇聚会时拿⼀块H*W的巧克⼒招待来的K个⼩朋友,保证每位⼩朋 友⾄少能获得⼀块相同⼤⼩的巧克⼒ 。那么⼩杨想分出来最⼤边长的巧克⼒可 以使⽤⼆分法。

答案:错误

解析:因为考纲中对二分法同时列出了“二分查找”和“二分答案(或二分枚 举)”。

3、以下C++代码能以递归⽅式实现斐波那契数列 ,该数列第1 、2项为1, 以 后各项均是前两项之和 。

答案:错误

解析:哪来的fiboA和fiboB

4、贪⼼算法可以达到局部最优 ,但可能不是全局最优解 。

答案:正确

解析:贪心是一直做当前最好的选择,可以达到局部最优,但在前边影响后边的题目可能不是全局最优

5、⼩杨设计了⼀个拆数程序,它能够将任意的⾮质数⾃然数N转换成若⼲个质 数的乘积,这个程序是可以设计出来的。

答案:正确

解析:唯一分解定理是存在的,因此可以设计出来程序

6、插⼊排序有时⽐快速排序时间复杂度更低 。 ( )

答案:正确

解析:当数组已经有序,插入排序的时间复杂度为O(n),快速排序的时间复杂度为O(n^2),此时插入排序比快速排序快,因此正确。

7、下⾯的C++代码能实现⼗进制正整数N转换为⼋进制并输出 。 

答案:错误

解析:rst应该倒序存储才能使最低位靠后

8、对数组 int arr[]={2,6,3,5,4, 8,1,0, 9, 10} 执⾏ sort(arr, arr+10) ,则执⾏后 arr 中的数据调整为 {0,1,2,3,4,5,6,8,9,10} 。

答案:正确

std::sort在无自定义比较函数的情况下是默认从小到大排序的,而区间是包括左,不包括右的,因此sort的范围恰好布满arr,于是就排成了0 1 2 3 4 5 6 8 9(7被我吃了)

9、⼩杨想写⼀个程序来算出正整数N有多少个因数 ,经过思考他写出了⼀个 重复没有超过N/2次的循环就能够算 出来了 。

答案:正确

解析:可以枚举到n的一半因数,因为另一半没有因数啊啊啊!

10、同样的整数序列分别保存在单链表和双向链中 ,这两种链表上的简单冒泡 排序的复杂度相同。

答案:正确

解析:相邻数据交换,时间还是O(1),因此时间没啥区别

三、编程题(每道题25分,共50分)

1 小杨的幸运数(普及/提高-)

B3929 [GESP202312 五级] 小杨的幸运数 - 洛谷https://www.luogu.com.cn/problem/B3929

题目描述

小杨认为,所有大于等于 a 的完全平方数都是他的超级幸运数。

小杨还认为,所有超级幸运数的倍数都是他的幸运数。自然地,小杨的所有超级幸运数也都是幸运数。

对于一个非幸运数,小杨规定,可以将它一直 +1,直到它变成一个幸运数。我们把这个过程叫做幸运化。例如,如果a=4,那么 4 是最小的幸运数,而 1 不是,但我们可以连续对 1 做 3 次 +1 操作,使其变为 4,所以我们可以说, 1幸运化后的结果是 4。

现在,小杨给出 N 个数,请你首先判断它们是不是幸运数;接着,对于非幸运数,请你将它们幸运化。

输入格式

第一行 2 个正整数 a,N。

接下来 N 行,每行一个正整数 x ,表示需要判断(幸运化)的数。

输出格式

输出 N 行,对于每个给定的 x ,如果它是幸运数,请输出 lucky,否则请输出将其幸运化后的结果。

输入输出样例

输入 #1

2 4 
1 
4 
5 
9

输出 #1

4 
lucky 
8 
lucky

输入 #2

16 11 
1 
2 
4 
8 
16 
32 
64 
128 
256 
512
1024

输出 #2

16 
16 
16 
16 
lucky 
lucky 
lucky 
lucky 
lucky 
lucky 
lucky

说明/提示

样例解释 1

1 虽然是完全平方数,但它小于 a,因此它并不是超级幸运数,也不是幸运数。将其进行 3 次 +1 操作后,最终得到幸运数 4。4 是幸运数,因此直接输出 lucky 。

5 不是幸运数,将其进行 3 次 +1 操作后,最终得到幸运数 8。

9 是幸运数,因此直接输出 lucky 。

数据规模

对于 30% 的测试点,保证 a,x≤100,N≤100。

对于 60% 的测试点,保证 a,x≤106。

对于所有测试点,保证 a≤1,000,000;保证 N≤2×105;保证 1≤x≤1,000,001。

题目大意

任何大于等于a的完全平方数的倍数都叫幸运数,可以是1倍。

对于非幸运数,可以一直+1,直到幸运为止,这叫幸运化。

输入n个数,如果是幸运数则输出lucky,否则输出他幸运化的值。

题目分析

我们可以设一个bool数组lucky,lucky[i]表示i是否为幸运数,是则true,否则false。

接下来输入,对于每个输入的数字x,去检查lucky[x]是否true,如果true,就输出lucky;

反之,用i从x+1开始枚举到1000001(数据最大值),去检查每个lucky[i],如果true就输出并break

由于幸运数比较多,所以可以赌一把时间,本人亲测可AC。

解题步骤

1 读入a N并计算lucky[1000002]数组

2 读入每个x并向后寻找幸运数

1 读入aN并计算lucky

读入aN直接cin>>a>>n;就可以了。

然后用i从ceil(sqrt(a))开始,结束条件为i*i<=1000001,每次i++

这样做的目的是枚举从a到1000001的完全平方数,但是时间慢,于是就从平方根开始,这样时间就能大打折扣!

ceil是向上取整,因为要大于等于a,如果不加ceil就是向下取整,那样就不对了!

所以此时i就代表了i*i,一会i的各种操作都要用i*i代替。

我们枚举的是超级幸运数,于是还要通过j(倍数)来获取i*i*j,如果<=1000001,就可以标记为"幸运"

如果大于,直接BREAK!!!

代码:

bool lucky[1000002];
void work(int a)
{for(int i=ceil(sqrt(a));i*i<=1000001;i++){for(int j=1;i*i*j<=1000001;j++){lucky[i*i*j]=1;}}
}

其中work为求lucky的函数

2 读入x并寻找幸运数

这个...我觉得没必要多说了吧,看代码吧~

for(int i=1;i<=n;i++)
{int x;cin>>x;if(lucky[x])cout<<"lucky\n";else{for(int j=x+1;j<=1000001;j++){if(lucky[j]){cout<<j<<endl;break;}}}
}

完整代码

#include<bits/stdc++.h>
using namespace std;
bool lucky[1000002];
void work(int a)
{for(int i=ceil(sqrt(a));i*i<=1000001;i++){for(int j=1;i*i*j<=1000001;j++){lucky[i*i*j]=1;}}
}
int main()
{int a,n;cin>>a>>n;work(a);for(int i=1;i<=n;i++){int x;cin>>x;if(lucky[x])cout<<"lucky\n";else{for(int j=x+1;j<=1000001;j++){if(lucky[j]){cout<<j<<endl;break;}}}}return 0;
}

AC截图

总结

这题不难,稍加分析就能AC,但是代码的长度,我看普及/提高-也值得。

小杨你明天出个倒霉数行不~

2 烹饪问题(普及/提高-)

B3930 [GESP202312 五级] 烹饪问题 - 洛谷https://www.luogu.com.cn/problem/B3930

题目描述

有 N 种食材,编号从 1 至 N,其中第 i 种食材的美味度为 ai​。

不同食材之间的组合可能产生奇妙的化学反应。具体来说,如果两种食材的美味度分别为 x 和 y ,那么它们的契合度为 x and y。

其中,and 运算为按位与运算,需要先将两个运算数转换为二进制,然后在高位补足 ,再逐位进行与运算。例如,12 与 6 的二进制表示分别为 1100 和 0110 ,将它们逐位进行与运算,得到 0100 ,转换为十进制得到 4,因此 12 and 6=4。在 C++ 或 Python 中,可以直接使用 & 运算符表示与运算。

现在,请你找到契合度最高的两种食材,并输出它们的契合度。

输入格式

第一行一个整数 N,表示食材的种数。

接下来一行 N 个用空格隔开的整数,依次为 a1​,⋯,aN​,表示各种食材的美味度。

输出格式

输出一行一个整数,表示最高的契合度。

输入输出样例

输入 #1

3
1 2 3

输出 #1

2

输入 #2

5
5 6 2 10 13

输出 #2

8

说明/提示

样例解释 1

可以编号为 1,2 的食材之间的契合度为 2 and 3=2,是所有食材两两之间最高的契合度。

样例解释 2

可以编号为 3,4 的食材之间的契合度为 10 and 13=8,是所有食材两两之间最高的契合度。

数据范围

对于 40% 的测试点,保证 N≤1,000;

对于所有测试点,保证 N≤10^6,0≤ai​≤2,147,483,647。

TLE做法

有些孩子上来就暴力枚举食材,然后两两求值取最大,代码往往一成不变地长这样:

#include<bits/stdc++.h>
using namespace std;
int a[1000001];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];int mx=0;for(int i=1;i<n;i++){for(int j=i+1;j<=n;j++){mx=max(mx,a[i]&a[j]);}}cout<<mx;return 0;
}

恭喜你!TLE了~别着急,我们来分析一下题目。

题目大意

给定n个正整数,求他们两两组合的最大按位与值。

题目分析

我们可以暴力枚举食材,然后求最大的与值。但是这样会TLE超时,因此我们不妨换个思路:

倒序排序,然后看前32个数进行暴力就行了,时间复杂度...O(nlogn),因为排序。

接下来看我证明~

众所周知,两个数按位与的最高位最高是两个数中的更低位。

倒序排序,高位就越有可能是1,而数据一共是32位。

前32个数字肯定能覆盖所有位,因为如果位数全不同,那么每个位都覆盖到,如果有相同,就会更完整地覆盖向下的位,注意所有位指的是所有数的最高位,以二进制为准。

OK现在只需要前32个数字,那么这样除了排序外,剩下部分的时间复杂度就是O(n)读入和O(1)计算了。

解题步骤

1 读入数据并排序

2 n的值缩小并暴力

1 读入数据并排序

这个没啥好说的

int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1,greater<int>());

这里的greater<int>()其实是C++标准库提供的自定义比较函数:大于,小于就是less。

大于就是我们想要的相邻元素关系,这就相当于倒序。

2 n的值缩小并暴力

这个没有说的吧~

n=min(n,32);
int mx=0;
for(int i=1;i<n;i++)
{for(int j=i+1;j<=n;j++){mx=max(mx,a[i]&a[j]);}
}
cout<<mx;
return 0;

min和max都是std提供的最小最大函数,用于求两个数之间谁更大谁更小。

完整代码

#include<bits/stdc++.h>
using namespace std;
int a[1000001];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];sort(a+1,a+n+1,greater<int>());n=min(n,32);int mx=0;for(int i=1;i<n;i++){for(int j=i+1;j<=n;j++){mx=max(mx,a[i]&a[j]);}}cout<<mx;return 0;
}

AC截图

总结

这题比较复杂,有点考验数学能力,尤其是前32个数字的证明,完全就是二进制运算的高级用法!

结语

祝各位考生在考场上超常发挥,斩获高分!

http://www.dtcms.com/a/357247.html

相关文章:

  • 嵌入式-定时器的输入捕获,超声波获距实验-Day23
  • 如何使用 Vector 连接 Easysearch
  • 【实时Linux实战系列】实时环境监控系统的架构与实现
  • PPT处理控件Aspose.Slides教程:使用 C# 编程将 PPTX 转换为 XML
  • 【实时Linux实战系列】基于实时Linux的虚拟现实应用开发
  • 趣味学Rust基础篇(所有权)
  • 【DeepSeek】公司内网部署离线deepseek+docker+ragflow本地模型实战
  • 《跳出“技术堆砌”陷阱,构建可演进的软件系统》
  • 【PyTorch】神经风格迁移项目
  • 每周资讯 | 《恋与深空》获科隆游戏展2025“最佳移动游戏奖”;8月173个版号下发
  • 【小白笔记】访问GitHub 账户的权限英文单词解释
  • nvm使用和node使用
  • 【前端教程】用 JavaScript 实现4个常用时间与颜色交互功能
  • centos8部署miniconda、nodejs
  • webpack升级
  • 飞牛Nas每天定时加密数据备份到网盘,基于restic的Backrest笔记分享
  • linux和RTOS架构区别
  • 通过 KafkaMQ 接入Skywalking 数据最佳实践
  • JAVA:Spring Boot 集成 Easy Rules 实现规则引擎
  • 滚珠导轨如何赋能精密制造?
  • 【数据分享】省级人工智能发展水平综合指标体系(2011-2022)
  • 安卓开发---BaseAdapter(定制ListView的界面)
  • 基于SpringBoot和Thymeleaf开发的英语学习网站
  • 笔记本电脑频繁出现 vcomp140.dll丢失怎么办?结合移动设备特性,提供适配性强的修复方案
  • C#连接SQL-Server数据库超详细讲解以及防SQL注入
  • LSTM实战:回归 - 实现交通流预测
  • 保护海外服务器免受黑客攻击的方法
  • WebSocket功能完整解析
  • Linux系统——EXT2 文件系统
  • 【论文阅读】Sparse4D v2:Recurrent Temporal Fusion with Sparse Model