CCF编程能力等级认证GESP—C++5级—20231209

CCF编程能力等级认证GESP—C++5级—20231209

  • 单选题(每题 2 分,共 30 分)
  • 判断题(每题 2 分,共 20 分)
  • 编程题 (每题 25 分,共 50 分)
    • 小杨的幸运数
    • 烹饪问题
  • 答案及解析
    • 单选题
    • 判断题
    • 编程题1
    • 编程题2

单选题(每题 2 分,共 30 分)

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

int fiboA(int N){
	if (N == 1 || N == 2)
		return 1;
	return fiboA(N - 1) + fiboA(N - 2);
}
int fiboB(int N){
	if (N == 1 || N == 2)
		return 1;
	int last2 = 1, last1 = 1;
	int nowVal = 0;
	for (int i = 2; i < N; i++){
		nowVal = last1 + last2;
		last2 = last1;
		last1 = nowVal;
	}
	return nowVal;
}
A. fiboA( ) 用递归方式, fiboB() 循环方式
B. fiboA( ) 更加符合斐波那契数列的数学定义,直观易于理解,而 fiboB() 需要将数学定义转换为计算机程序实现
C. fiboA( ) 不仅仅更加符合数学定义,直观易于理解,且因代码量较少执行效率更高
D. fiboB( ) 虽然代码量有所增加,但其执行效率更高

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

void mergeSort(int SList[], int TList[], int s, int t, int len){
	if (s == t){
		TList[s] = SList[s];
		return;
	}
	int *T2 = new int[len]; // 保存中间结果
	int m = (s + t) / 2;
	________; 
	merge(T2, SList, s, m, t);
	delete T2;
	return; 
}  
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)

3、阅读下面的C++代码,执行后其输出是( )。

int stepCount = 0;
int fracA(int N){
	stepCount += 1;
	cout << stepCount << "->";
	int rtn = 1;
	for (int i = 1; i <= N; i++)
		rtn *= i;
	return rtn;
}
int fracB(int N){
	stepCount += 1;
	cout << stepCount << "->";
	if (N == 1)
		return 1;
	return N * fracB(N - 1);
}
int main() {
	cout << fracA(5);
	cout << "<===>";
	cout << fracB(5);
    return 0;
}
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

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

bool isEven(int N){
	return N % 2 == 0;
}
void swap(int &a, int &b){
	int t;
	t = a, a = b, b = t;
	return;
}
void sortA(int lstA[], int n){
	int i, j, t;
	for (i = n - 1; i > 0; i--)
		for (j = 0; j < i; j++)
			if (____)
				swap(lstA[j], lstA[j + 1]);
	return;
}
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]

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

typedef struct Node{
	string str;
	int ref;
	struct Node *next, *prev;
}Node;
Node * Insert(Node *pHead, string s){
	Node *p = pHead->next;
	Node *q;
	while (p){
		if (p->str == s){
			p->ref++;
			p->next->prev = p->prev;
			p->prev->prev = p->next;
			break;
		}
		p = p->next;
	}
	if (!p){
		p = new Node;
		p->str = s;
		p->ref = 0;
		p->next = p->prev = NULL;
	}
	________
	pHead->next = p, p->prev = pHead;
	return pHead;
}
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. 触发异常,不能对空指针进行操作。

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

int rc;
int foo (int x, int y){
	int r;
	if (y == 0)
		r = x;
	else{
		r = foo(y, x % y);
		rc++;
	}
	return r;
}
A. 如果 x 小于10, rc 值也不会超过20
B. foo 可能无限递归
C. foo 可以求出 x 和 y 的最大公共质因子
D. foo 能够求出 x 和 y 的最小公倍数

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

vector<int> operator +(vector<int>lA, vector<int>lB){
	vector<int>lst;
	for (inti = 1; i < lA.size(); i++)
		lst.push_back(lA[i]);
	for (inti = 1; i < lB.size(); i++)
		lst.push_back(lB[i]);
	return lst;
}
vector<int>qSort(vector<int>lst){
	if (lst.size() < 2)
		return lst;
	int pivot = lst[0];
	vector<int>less, greater;
	for (int i = 1; i < lst.size(); i++)
		if(lst[i] <= pivot) less.push_back(lst[i]);
		else greater.push_back(lst[i]);
	for (int i = 1; i < lst.size(); i++)
		if(lst[i] <= pivot) less.push_back(lst[i]);
		else greater.push_back(lst[i]);
	return ________;
}
A. qSort(less) + qSort(greater) + (vector<int>)pivot
B. (vector<int>)pivot + (qSort(less) + qSort(greater))
C. (qSort(less) + (vector<int>)pivot + qSort(greater))
D. qSort(less) + pivot + qSort(greater)

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

bool isPrimeA(int N){
	if (N < 2)
		return false;
	for (int i = 2; i <= N / 2; i++)
		if (N % i == 0)
			return false;
	return true;
}
bool isPrimeB(int N){
	if (N < 2)
		return false;
	for (int i = 2; i <= sqrt(N); i++)
		if (N % i == 0)
			return false;
	return true;
}
A. isPrimeA() 的最坏时间复杂度是O(N/2)isPrimeB( ) 的最坏时间复杂度是O(logN)isPrimeA() 优于 isPrimeB()
B. isPrimeA() 的最坏时间复杂度是O(N/2)isPrimeB( ) 的最坏时间复杂度是O(N^(1/2))isPrimeB() 绝大多数情况下优于 isPrimeA()
C. isPrimeA() 的最坏时间复杂度是O(N^(1/2))isPrimeB( ) 的最坏时间复杂度是O(N)isPrimeA( ) 优于isPrimeB( )
D. isPrimeA() 的最坏时间复杂度是O(logN)isPrimeB( ) 的最坏时间复杂度是O(N)isPrimeA() 优于isPrimeB( )

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

int _binarySearch(vector<int>lst, int Low, int High, int Target){
	if (Low > High)
		return -1;
	int Mid = (Low + High) / 2;
	if (Target == lst[Mid])
		return Mid;
	else if (Target < lst[Mid])
		return _binarySearch(lst, Low, Mid - 1, Target);
	else
		return _binarySearch(lst, Mid + 1, High, Target);
}
int bSearch(vector<int>lst, int Val){
	return _binarySearch(lst, 0, lst.size(), Val);
}
A. 代码采用二分法实现有序 list 的查找
B. 代码采用分治算法实现有序 list 的查找
C. 代码采用递归方式实现有序 list 的查找
D. 代码采用动态规划算法实现有序 list 的查找

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

A. O(N)
B. O(logN)
C. O(NlogN)
D. O(N^2)

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

vector<int> operator +(vector<int> a, vector<int> b){
	vector<int> c;
	int t = 0;
	for (int i = 0; i < a.size() || i < b.size(); i++){
		if (i < a.size()) t = t + a[i];
		if (i < b.size()) t = t + b[i];
		________
	}
	if (t) c.push_back(t);
	return 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;

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

class Node{
public:
		int Value;
		Node* Prev;
		Node* Next;
		Node(int Val, Node* Prv = NULL, Node* Nxt = NULL);
};
Node::Node(int Val, Node*Prv, Node* Nxt){
	this->Value = Val;
	this->Prev = Prv;
	this->Next = Nxt;	
}
int main() {
	Node firstNode = Node(10);
	firstNode.Next = new Node(100, &firstNode);
	firstNode.Next->Next = new Node(111, firstNode.Next);
}
A. 上述代码构成单向链表
B. 上述代码构成双向链表
C. 上述代码构成循环链表
D. 上述代码构成指针链表

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

A. 信息过滤
B. 信号中继
C. 避免攻击
D. 数据加密

14、小杨想编写一个判断任意输入的整数N是否为素数的程序,下面哪个方法不合适?( )

A. 埃氏筛法
B. 线性筛法
C. 二分答案
D. 枚举法

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

A. 选择排序
B. 快速排序
C. 堆排序
D. 冒泡排序

判断题(每题 2 分,共 20 分)

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

2、小杨在生日聚会时拿一块H*W的巧克力招待来的K个小朋友,保证每位小朋友至少能获得一块相同大小的巧克力。那么小杨想分出来最大边长的巧克力可以使用二分法。( )

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

int Fibo(int N){
	if (N == 1 || N == 2)
		return 1;
	else{
		int m = fiboA(N - 1);
		int n = fiboB(N - 2);
		return m + n;
	}
}

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

5、小杨设计了一个拆数程序,它能够将任意的非质数自然数N转换成若干个质数的乘积,这个程序是可以设计出来的。( )

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

7、下面的C++代码能实现十进制正整数N转换为八进制并输出。( )

char s[10];
int main() {
	int N;
	cin >> N;
	string rst = "";
	while (N != 0){
		s[0] = N % 8 + '0';
		rst += string(s);
		N /= 8;
	}
	cout << rst << endl;
	return 0;
}

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} 。( )

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

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

编程题 (每题 25 分,共 50 分)

小杨的幸运数

【问题描述】
小杨认为,所有大于等于 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
【样例解释 1】
1虽然是完全平方数,但它小于a ,因此它并不是超级幸运数,也不是幸运数。将其进行 3 次+1 操作后,最终得到幸运数4 。
4是幸运数,因此直接输出 lucky 。
5不是幸运数,将其进行 3 次 +1 操作后,最终得到幸运数8 。
9是幸运数,因此直接输出 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
【数据规模】
对于30%的测试点,保证a,x <= 100 ,N <= 100 。
对于60%的测试点,保证a, x <= 1 0 6 10^6 106
对于所有测试点,保证a <=1,000,001 ;保证 N < = 2 ∗ 1 0 5 N<=2*10^5 N<=2105 ;保证1 <= x <= 1,000,001 。

烹饪问题

【问题描述】
有 N 种食材,编号从 0 至 N - 1 ,其中第 i 种食材的美味度为ai 。
不同食材之间的组合可能产生奇妙的化学反应。具体来说,如果两种食材的美味度分别为x 和y ,那么它们的契合度为x and y 。
其中, and运算为按位与运算,需要先将两个运算数转换为二进制,然后在高位补足0 ,再逐位进行与运算。例如,12与6 的二进制表示分别为 1100 和 0110 ,将它们逐位进行与运算,得到 0100 ,转换为十进制得到4 ,因此12 and 6 = 4。在 C++ 或Python 中,可以直接使用 & 运算符表示与运算。
现在,请你找到契合度最高的两种食材,并输出它们的契合度。
【输入描述】
第一行一个整数 N ,表示食材的种数。
接下来一行 N 个用空格隔开的整数,依次为 a 0 , . . . , a N − 1 a_0, ..., a_{N-1} a0,...,aN1 ,表示各种食材的美味度。
【输出描述】
输出一行一个整数,表示最高的契合度。
【特别提醒】
在常规程序中,输入、输出时提供提示是好习惯。但在本场考试中,由于系统限定,请不要在输入、输出中附带任何提示信息。
【样例输入 1】
3
1 2 3
【样例输出 1】
2
【样例解释 1】
可以编号为1,2 的食材之间的契合度为2 and 3 = 2 ,是所有食材两两之间最高的契合度。
【样例输入 2】
5
5 6 2 10 13
【样例输出 2】
8
【样例解释 2】
可以编号为3,4 的食材之间的契合度为10 and 13 = 8 ,是所有食材两两之间最高的契合度。
【数据规模】
对于40%的测试点,保证N <= 1,000 ;
对于所有测试点,保证N <= 1 0 6 10^6 106 ,0 <= a i a_i ai <= 2,147,483, 647 。

答案及解析

单选题

1、
【答案】C
【考纲知识点】算法知识点
【解析】fiboA 是很好理解的,但是执行效率不高,有的计算是重复的,导致效率低。

2、
【答案】C
【考纲知识点】算法知识点
【解析】本题考察归并排序。归并排序需要先将排序序列一分为二,左边的元素的区间是[s,m],右边元素区间是[m+1,t],然后递归排序两个子序列后,将有序的子序列合并。

3、
【答案】D
【考纲知识点】算法知识点
【解析】本题考察递归算法。输出 fracA 函数,是先输出1,再输出5 的阶乘,120;23行代码,执行fracB函数,此时stepCount从2开始计数,依次输出2/3/4/5/6,再输出 5 的阶乘 120。

4、
【答案】A
【考纲知识点】排序算法知识点
【解析】本题考察排序算法。前一个数字,下标是 j 的数字是偶数,后面的数字下标是 j+1 的是奇数,按照要求,偶数在奇数的后面,要交换。A 符合题意条件。

5、
【答案】B
【考纲知识点】指针知识点
【解析】本题考察双链表知识点。每个节点需要 2 个指针,指向前驱节点和后继节点。按照要求,新的节点要求插入到链表头部。头节点和新插入的节点都需要修改。B 选项能够完成新节点的插入。

6、
【答案】A
【考纲知识点】数学知识点
【解析】本题考察数学算法,求最大公约数。这是典型的最大公约数写法的变形。排除法选 A。

7、
【答案】C
【考纲知识点】排序算法知识点
【解析】本题考察快速排序。Less 数组保存的是小于等于pivot,然后加上pivot
元素,再加上大于等于 pivot 的数组。

8、
【答案】B
【考纲知识点】数学知识点
【解析】本题考察数学知识,判断质数。A 函数时间复杂度是O(n/2),B 函数算法是 O(sqrt(n)),大部分情况后者是优的,值更小。

9、
【答案】D
【考纲知识点】算法知识点
【解析】本题考察算法知识点。二分法每次规模减半,查找平均时间复杂度是B。

10、
【答案】B
【考纲知识点】算法知识点
【解析】本题考察算法知识点。二分法每次规模减半,单词查找平均时间复杂度是 B。

11、
【答案】D
【考纲知识点】算法知识点
【解析】本题考察高精度知识点。每次保存对应位和的最低位数字,去掉最低位数字后,保持进位,循环执行。

12、
【答案】B
【考纲知识点】链表知识点
【解析】本题考察链表知识点。每个节点指向自己前一个节点和后一个节点,因此是双向链表。

13、
【答案】B
【考纲知识点】计算机基础知识
【解析】本题考察计算机基础知识。通信卫星可以转发无线电信号,实现通信地球站间或地球站与航天器间的无线电通信,因此具有信号中继作用。选B。

14、
【答案】C
【考纲知识点】数学知识
【解析】本题考察数学知识。线筛和埃筛都可以判断素数,枚举也可以,二分规模减半,不能合理判断。

15、
【答案】B
【考纲知识点】排序算法知识
【解析】本题考察排序算法知识。需要了解每种排序算法的特点。快速排序是选定一个数字,每次把比它小的放在左边,比元素大的放在右边,不能确定最值。

判断题

1、
【答案】正确
【考纲知识点】排序算法知识
【解析】本题考察排序算法知识。归并排序算法的时间复杂度的描述正确。

2、
【答案】错误
【考纲知识点】算法知识
【解析】因为考纲中对二分法同时列出了“二分查找”和“二分答案(或二分枚举)”。

3、
【答案】错误
【考纲知识点】算法知识
【解析】本题考察递归算法知识。递归函数要调用自己。

4、
【答案】正确
【考纲知识点】算法知识
【解析】本题考察贪心算法知识。贪心是局部达到最优。

5、
【答案】正确
【考纲知识点】数学知识
【解析】本题考察数学知识。素数分解定理规定:任何一个整数都可以被分解为一系列因子的乘积,乘积中所有的因子都是质数(即素数)。(更严谨一点:大于1的整数)

6、
【答案】正确
【考纲知识点】排序知识
【解析】本题考察排序算法知识。当数据初始有序时,插入排序的最快时间复杂度是 O(n),快排最坏时间复杂度是 O(N2)。

7、
【答案】错误
【考纲知识点】计算机基础知识
【解析】本题考察进制转换知识。转换后的内容要倒序输出并以0 开头。

8、
【答案】正确
【考纲知识点】排序知识
【解析】本题考察排序算法知识。sort 默认是从小到大排序。

9、
【答案】正确
【考纲知识点】数学知识
【解析】本题考察数学知识。可以循环 N 的一半找到所有因数。

10、
【答案】正确
【考纲知识点】排序算法知识
【解析】本题考察排序算法知识。冒泡排序,相邻的数据交换,而且修改节点链的操作不会改变复杂度。

编程题1

1、
【题目大意】给一个完全平方数的标准,推导出哪些是超级幸运数,然后判断N个数字中,哪些是超级幸运数,是的输出“lucky”,不是的输出离该数字最近的比它大的数字。
【考纲知识点】数学知识,埃筛知识,循环知识
【解题思路】完全平方数按照定义,包括 1,4,9,16,25……。超级幸运数还可以是完全平方数的倍数,因此 8,12,18……也是超级幸运数。数据范围比较大,1e6,用埃筛的模板,判断每一个数字是否是幸运数字。不是幸运数字的话,保留离它最近的幸运数字作为答案。最终完成整个查询。


编程题2

2、
【题目大意】选出 2 个数字,求出这 2 个数字与操作的最大结果是多少。【考纲知识点】位运算知识,循环知识,排序知识
【解题思路】需要选取 2 个数字,可以用双重循环枚举这2 个数字,取最大值,最终得到答案。对于前 40%的测试点是可以的。当数据量大的时候,就超时了。我们知道,两个数字对应的二进制,位数越高是 1,越有可能是答案。所以从最高位统计,是否至少有 2 个数字最高位是 1,保存最高位结果,并且把最高位非1 的数字删去;再查询次高位是否至少有 2 个以上的数字二进制位都是1,以此类推,求出哪 2 个数字与 结果最大。利用快速排序的方法每次将剩余数字中当前考虑的位为 1 的数字放在前面,时间复杂度是 O(N*log(a_i 值的最大值))。


你可能感兴趣的:(#,C++,-,5级,c++,java,算法)