CCF编程能力等级认证GESP—C++4级—20240316

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

1、若函数声明为 int f(int &x){ x+=3; return x; } ,则对声明的变量 int a=3 ,下面哪个调用能够改变 a 的值( )。

A. f(&a) ; 
B. f(*a) ;
C. f(a) ;
D. f(a-3) ;

正确答案:C

函数 int f(int &x) 的参数 x 是一个引用类型,这意味着当你传递一个变量给这个函数时,你实际上是传递了这个变量的引用,而不是它的值。因此,在函数内部对 x 所做的任何修改都会反映到原始变量上。
A选项:这是错误的,因为 &a 是一个指向 a 的指针,而函数 f 期望的是一个整数的引用,不是指针。
B选项:这也是错误的,因为 a 是一个整数,你不能对它使用解引用操作符 *
C选项:这是正确的。当你传递 a 给函数 f 时,你实际上传递了 a 的引用。因此,在函数内部对 x(即 a 的引用)所做的修改(x += 3)会改变 a 的值。
D选项:这是错误的,因为 a-3 是一个表达式,它的结果是一个临时值,你不能对临时值取引用。

2、下面C++代码执行后,输出的是( )。

int main(){
	int x[] = {2, 0, 2, 4};
	char geSP[] = "Grade Examination of SP";
	
	cout << geSP[sizeof(x)] << endl; 
	cout << endl;
	return 0;
}
A. G 
B. e 
C. n 
D. P

正确答案:C

首先,sizeof(x) 返回数组 x 的大小(以字节为单位)。数组 x 是一个整型数组,包含4个整数。在大多数现代系统上,一个整数(int)通常是4字节。因此,sizeof(x) 的值将是 4 * 4 = 16
然后,geSP[sizeof(x)] 访问 geSP 字符串数组中索引为16的字符,即 n。
因此,代码 cout << geSP[sizeof(x)] << endl; 将输出字符 n,后跟一个换行符。所以正确答案是 C。

3、下面C++代码执行后输出是( )。

int foo(float *f)
{
    return int(*f * 2);
}
int main(){
	float fnum[10] = {1.1};
	fnum[1] = foo(fnum);
	cout << fnum[0] + fnum[1] << endl;
	
	cout << endl;
	return 0;
}
A. 1 
B. 1.1 
C. 3 
D. 3.1

正确答案:D

首先,foo 函数接收一个指向 float 的指针 f,然后返回 *f * 2 的整数值。注意这里有一个隐式类型转换,因为 *f * 2 的结果是 float 类型,但函数返回类型是 int,所以结果会被转换为整数。
main 函数中,fnum 是一个包含10个 float 的数组,其中 fnum[0] 被初始化为 1.1,其他元素默认初始化为 0.0
然后调用 foo(fnum),这里传递的是数组 fnum 的首地址,即 &fnum[0]。因此,foo 函数中的 *f 实际上就是 fnum[0],其值为 1.1
foo(fnum) 返回 int(1.1 * 2),即 int(2.2),结果是 2(因为 2.2 被转换为整数时,小数部分被丢弃)。
接下来,fnum[1] = foo(fnum);fnum[1] 的值设置为 2
最后,cout << fnum[0] + fnum[1] << endl; 输出 fnum[0]fnum[1] 的和,即 1.1 + 2.0 = 3.1

4、对二维数组 int arr[3][16]; ,则 arr[1] 占用内存的大小为( )字节。

A. 4
B. 16 
C. 48 
D. 64

正确答案:D

在C++中,数组的内存占用取决于其元素的数据类型和数组的大小。对于给定的二维数组 int arr[3][16];,每个元素都是一个 int 类型。在大多数现代系统上(特别是使用32位或64位架构的系统),int 类型的大小通常是4字节。
数组 arr 是一个包含3个元素的数组,每个元素又是一个包含16个 int 的数组。所以,arr[1](即 arr 的第二个子数组)是一个包含16个 int 的数组。
因此,arr[1] 占用内存的大小是 16(元素数量) * 4(每个元素的大小)= 64 字节。

5、对二维数组 int arr[3][16]; ,若 arr 的地址是 0x28cbc0 ,则 arr[1] 的值是( )。

A. 0x28cbc4
B. 0x28cbd0 
C. 0x28cc00 
D. 不确定

正确答案:C

对于二维数组 int arr[3][16];,我们知道每个整数(int)通常占用4字节(在大多数现代系统上)。因此,整个数组 arr 在内存中是连续存储的。
给定 arr 的地址是 0x28cbc0,我们可以计算 arr[1] 的地址。
arr[0] 占用 16 * 4 = 64 字节(因为 arr[0] 是一个包含16个整数的数组)。
因此,arr[1] 的地址是 arr 的地址加上 arr[0] 所占用的字节数:
0x28cbc0 + 64 = 0x28cc00
所以,arr[1] 的地址是 0x28cc00,答案是 C。
注意:这里我们讨论的是地址,而不是值。arr[1] 本身是一个数组,不是一个具体的整数值。当我们说 arr[1] 的地址时,我们是指这个数组在内存中的起始位置。

6、下面C++代码执行后输出是( )。

int main(){
	char *p = "I love GESP!";
	cout << p + 5 << endl;
	
	cout << endl;
	return 0;
}
A. e
B. I lov 
C. e GESP! 
D. GESP!

正确答案:C

在C++中,字符串字面量如 "I love GESP!" 实际上是一个字符数组,并且存储在程序的只读数据段中。当你声明一个指向字符的指针 char *p = "I love GESP!"; 时,p 指向这个字符数组的第一个元素,即字符 'I'。
表达式 p + 5 将指针向前移动5个位置,因此它现在指向字符串中第6个字符的位置,即 'e'。
当你使用 cout 输出 p + 5 时,它会从当前指针位置开始输出字符串,直到遇到字符串结束符 '\0'。因此,输出将从 'e' 开始,并继续输出后面的所有字符,即 "e GESP!"。

7、下面C++代码执行以后输出的是( )。

int rc = 5;
int main(){
	int rc;
	cout << ++rc << endl;
	
	cout << endl;
	return 0;
}
A. 0
B. 1
C. 6
D. 不确定

正确答案:D

在C++中,变量具有作用域和生命周期。在这个例子中,全局变量 rc 和局部变量 rc 有着相同的名字,但它们的作用域不同。全局变量 rc 在整个程序中都是可见的,而局部变量 rc 只在 main 函数的作用域内可见。
main 函数中,当声明局部变量 int rc; 时,它隐藏了全局变量 rc。因此,在 main 函数内部,任何对 rc 的引用都将指向局部变量,而不是全局变量。
局部变量 rc 在声明时没有被初始化,因此它有一个不确定的值(在C++中,局部变量如果没有显式初始化,则它们的值是未定义的)。然后,代码执行 ++rc,这将导致未定义的行为,因为 rc 的初始值是未知的。
因此,输出是不确定的,答案是 D。
注意:在实际编程中,应该避免使用相同的名字来命名全局变量和局部变量,因为这会导致混淆和可能的错误。

8、下面C++函数中采用的算法是( )。

int fib(int n){
	int i, f[n] = {0, 1}; 
	for(int i = 2; i <= n; i++)
		f[i] = f[i - 1] + f[i - 2];
	
	return f[n]; 
}
A. 递推 
B. 递归 
C. 迭代 
D. 循环

正确答案:A

虽然这个问题中的函数使用了循环(for循环)来执行计算,但该函数的核心算法是递推。递推是一种从已知的初始条件出发,根据一定的递推关系(即前一项或前几项与后一项之间的关系),逐项推导出序列中未知项的算法。
在这个函数中,f[i] 的值是通过 f[i - 1] 和 f[i - 2] 的值计算出来的,这符合递推算法的定义。虽然函数内部使用了循环来执行递推过程,但算法的本质是递推。

9、插入排序在最好情况下的时间复杂度是( )。

A . O ( 1 ) A. O(1) A.O(1)
B . O ( N / 2 ) B. O(N / 2) B.O(N/2)
C . O ( N ) C. O(N) C.O(N)
D . O ( N 2 ) D. O(N^2) D.O(N2)

正确答案:C

插入排序的基本思想是:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
在最好情况下(即输入序列已经是排好序的),每次只需要比较一次,就可以确定插入的位置。但由于仍然需要遍历整个序列(虽然不需要移动元素),因此最好情况下的时间复杂度是 O(N),其中 N 是序列的长度。

10、在如下的C++代码执行后,设第11和12行的输出地址值分别为 X 和 Y ,则下面正确的是( )。

struct pass{
    int no;
    char name[20];
	int level; 
};
int main() {
	struct pass XiaoYang;
	cout << "&XiaoYang=" << &XiaoYang << endl; //第11行
	cout << "&(XiaoYang.no)=" << &(XiaoYang.no) << endl; //第12行
	cout << endl;
	return 0; 
}
A. X>Y 
B. X==Y 
C. X<Y 
D. 不确定

正确答案:B

在C++中,结构体(struct)是一个用户定义的数据类型,它允许你将不同类型的数据组合成一个单独的类型。在这个例子中,pass 结构体包含了三个成员:一个 int 类型的 no,一个 char 数组类型的 name,以及另一个 int 类型的 level
当在 main 函数中声明一个 pass 类型的变量 XiaoYang 时,这个变量在内存中占用一块连续的空间。&XiaoYang 表示整个 XiaoYang 结构体变量的地址,而 &(XiaoYang.no) 表示结构体中 no 成员变量的地址。
由于 noXiaoYang 结构体的第一个成员,它的地址实际上就是整个结构体地址的开始位置。在C++中,结构体成员的地址是相对于结构体起始地址的偏移量,而第一个成员的偏移量总是0,因此它的地址和整个结构体的地址是相同的。
所以,第11行和第12行的输出地址值 X 和 Y 是相等的。

11、如果文件 1.txt 中的内容如下,则执行下面C++代码时,注释了 #### 那行代码所输出的 x 的值为( )。

50 2024 3.16 I
love
GESP!
int main(){
	ifstream fin;
	string line;
	int x;
	fin.open("1.txt",ios::in);
	
	for (int i=0; i< 2; i++){
		fin >> line;
		cout << line << endl;
	}
	fin>>x;
	cout << x << endl; //####
	
	cout << endl;
	return 0;
}
A. 5
B. 2024 
C. 3
D. 0

正确答案:C

在这段C++代码中,首先通过ifstream类创建了一个文件输入流对象fin,并尝试打开名为"1.txt"的文件。
然后,程序进入一个for循环,循环两次。在每次循环中,程序都从文件中读取一个单词(或数字,直到空格、换行符或文件结束符)到line变量中,并输出它。
第一次循环读取的是"50",第二次循环读取的是"2024"。
接下来,程序尝试从文件中读取一个整数到变量x中。此时,文件流fin的当前位置是"2024"后面的空格之后,紧接着的是"3.16"。但是,因为fin >> x期望读取一个整数,它会尝试从"3.16"中读取一个整数,直到遇到不能构成整数的字符为止。在这种情况下,它会读取"3"作为整数部分,并将小数点及其后面的部分留在流中。
因此,变量x被赋值为3,所以注释了####的那行代码所输出的x的值为3。

12、执行下列C++代码时输出中的第2行是( )。

int main(){
	char *s[]={(char*)"2024",(char*)"3.16",(char*)"GESP"};
	for (int i=0; i< 2; i++){
		cout << *s+i << endl;
	} 
	cout << endl;
	return 0;
}
A. 2024 
B. 3.16 
C. 024 
D. 3

正确答案:C

在提供的C++代码中,s 是一个字符指针数组,它包含了三个字符串字面量的地址。
for 循环中,cout << *s+i << endl; 这行代码的行为需要仔细分析。*s 是数组 s 的第一个元素的解引用,即字符串 2024 的地址。然后 +i 将这个地址偏移 i 个字符的位置。
i0 时,*s+i 就是 2024 的起始地址,所以输出为 2024
i1 时,*s+i 指向 2024 的第二个字符 0。但是,由于 cout 会从该地址开始连续输出字符,直到遇到空字符 \0 为止,所以输出的是从 0 开始的子串 024。因此,输出中的第2行是 024

13、C++语言中下面哪个关键字能够限定对象的作用域( )。

A. extern
B. static 
C. inline 
D. public

正确答案:B

在C++语言中,static 关键字可以用来限定对象(包括变量和函数)的作用域。
A选项: extern 关键字用于声明一个变量或函数是在其他文件中定义的,而不是在当前文件中定义的。
B选项: static 关键字用于限制变量的可见性,使其只在定义它的文件内可见(对于文件作用域变量)或只在定义它的函数内可见(对于函数作用域变量)。对于类成员变量,static 关键字表示该变量是类的所有对象共享的静态成员。
C选项: inline 关键字建议编译器将函数内联,即将函数调用替换为函数体,以减少函数调用的开销。
D选项: public 是类的一个访问修饰符,用于指定类的成员(变量或函数)可以在类的外部被访问。
因此,能够限定对象作用域的关键字是 static

14、小杨的父母最近刚刚给他买了一块华为手表,他说手表上跑的是鸿蒙,这个鸿蒙是( )。

A. 小程序
B. 计时器 
C. 操作系统 
D. 神话人物

正确答案:C

华为手表上运行的鸿蒙(HarmonyOS)是一个分布式操作系统,由华为公司开发并发布。这个操作系统被设计为面向全场景的,可以链接手机、汽车、智能音箱、可穿戴设备等多种终端设备,并通过多设备交互让消费者能够像操作一台设备一样简单地操控多个设备。因此,鸿蒙在这里是一个操作系统。

15、中国计算机学会(CCF)在2024年1月27日的颁奖典礼上颁布了王选奖,王选先生的重大贡献是( )。

A. 制造自动驾驶汽车
B. 创立培训学校
C. 发明汉字激光照排系统
D. 成立方正公司

正确答案:C

王选先生是中国计算机汉字激光照排技术的创始人,被誉为“汉字激光照排系统之父”。他的这项发明对中国印刷出版业产生了深远影响,极大地提高了印刷质量和效率。

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

1、对 int a[]={2,0,2,4,3,1,6} ,执行第一趟选择排序处理后 a 中数据变为 {0,2,2,4,3,1,6} 。( )

正确答案:正确

选择排序(Selection Sort)算法的工作原理是:首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
对于数组 int a[]={2,0,2,4,3,1,6},如果我们执行第一趟选择排序,目的是找到整个数组中的最小值,并将其与数组的第一个元素交换。在这个数组中,最小值是0,它原来位于数组的第二个位置。按照选择排序的算法,我们会将这个最小值0与数组的第一个元素2交换位置。

2、如果待排序数据不能都装进内存,需要使用外排序算法。( )

正确答案:正确

外排序算法主要是用于处理那些太大而无法一次性装入内存的数据集。当待排序的数据量超过计算机内存的大小时,无法使用常规的内排序算法(如快速排序、归并排序等),因为这些算法都需要将数据全部加载到内存中。此时,就需要使用外排序算法。
外排序通常涉及两个主要阶段:首先是产生初始归并段(或称为“顺串”),然后是多路归并这些初始归并段以得到完全排序的文件。外排序算法需要考虑如何有效地利用磁盘I/O操作,因为磁盘访问速度远慢于内存访问速度,因此算法设计时需要尽量减少磁盘I/O次数。

3、定义变量int a=5,则cout << &++a会输出6。( )

正确答案:错误

首先,&++a 这个表达式中,++a 是前置递增操作,意味着先对 a 进行加 1 操作,然后再取 a 的地址。因此,a 的值会从 5 变为 6。
但是,cout << &++a 输出的不是 a 的值(即 6),而是 a 的地址。在 C++ 中,& 运算符用于获取变量的地址,而不是变量的值。因此,这个表达式会输出变量 a 的内存地址,而不是它的值 6。
所以,题目的说法“cout << &++a 会输出 6”是错误的。正确的输出应该是变量 a 的内存地址。

4、两个函数之间可以使用全局变量来传递数据。 ( )

正确答案:正确

全局变量是在整个程序范围内都可见的变量,它们不局限于任何特定的函数或代码块。由于全局变量的可见性,它们可以在程序的任何地方被访问和修改,包括在不同的函数之间。
因此,全局变量确实可以用于在不同的函数之间传递数据。当一个函数修改了全局变量的值,这个改变在其他函数中也是可见的,因为全局变量在所有函数之间共享。
然而,虽然全局变量可以用于函数间传递数据,但通常不建议过度使用全局变量,因为它们可能导致代码难以维护和理解,并可能引入意外的副作用和依赖关系。在可能的情况下,最好使用函数参数和返回值来传递数据。

5、定义数组 int a[2024][3][16]={2,0,2,4,3,1,6} ,则 cout << a[2023][2][15] 的结果不确定。( )

正确答案:错误

在 C++ 中,当你定义一个多维数组并只初始化部分元素时,未明确初始化的元素会被自动初始化为 0。对于数组 int a[2024][3][16],你只初始化了前 6 个元素,即 a[0][0][0], a[0][0][1], a[0][0][2], a[0][1][0], a[0][1][1], a[0][2][0] 分别被初始化为 2, 0, 2, 4, 3, 1。其余的元素都会被自动初始化为 0。
因此,a[2023][2][15] 这个元素在数组中的位置是确定的,并且由于它没有被显式初始化,它的值会被自动初始化为 0。所以 cout << a[2023][2][15] 的结果应该是确定的,即输出 0。

6、在C++语言中,函数的参数为指针时,可以在函数内部修改该参数的值。( )

正确答案:错误

在C++语言中,当函数的参数为指针时,你可以在函数内部通过指针来修改指针所指向的值,但你不能直接修改指针本身的值(即指针变量所存储的地址)。如果你尝试在函数内部修改指针的值(即让它指向一个新的地址),那么这种修改只会在函数内部有效,对函数外部的原始指针没有影响,因为函数接收的是指针的副本。

void modifyValue(int* ptr) {
    *ptr = 10; // 修改指针指向的值,这是可以的
    ptr = nullptr; // 修改指针本身的值,这不会影响函数外部的指针
}
int main() {
    int x = 5;
    int* p = &x;
    modifyValue(p);
    // 此时p仍然指向x,且x的值已经被修改为10
    // 但是p本身的值(即它的地址)并没有改变
    return 0;
}

在上面的例子中,modifyValue 函数接收一个指向整数的指针 ptr。在函数内部,我们通过 *ptr = 10; 修改了指针指向的值。然而,当我们尝试将 ptr 设置为 nullptr 时,这只是改变了函数内部 ptr 副本的值,对 main 函数中的 p 没有任何影响。

7、在C++语言中 try 子句里抛出的结构体等类型的异常无法被 catch 捕获。( )

正确答案:错误

在C++中,可以使用throw关键字抛出任意类型的异常,包括基本数据类型、结构体、类或对象等。相应地,catch子句也可以捕获这些类型的异常。因此,说“try 子句里抛出的结构体等类型的异常无法被 catch 捕获”是不正确的。
以下是一个简单的示例,展示了如何在C++中抛出和捕获一个结构体类型的异常:

#include <iostream>
using namespace std;
struct MyException {
    string message;
    MyException(const string& msg) : message(msg) {}
};
  
void functionThatMightThrow() {
    throw MyException("An error occurred!");
}
  
int main() {
    try {
        functionThatMightThrow();
    } catch (const MyException& e) {
        cout << "Caught exception: " << e.message << endl;
    }
    return 0;
}

在这个例子中,我们定义了一个名为MyException的结构体,它包含一个字符串成员message。在functionThatMightThrow函数中,我们抛出了一个MyException类型的异常。在main函数中,我们使用try-catch块来捕获这个异常,并打印出异常信息。

8、C++语言中 cout << 9^2 << endl; 会输出81。( )

正确答案:错误

在C++语言中,<< 是流插入运算符,用于向输出流(如 cout)发送数据。而 ^ 是按位异或运算符,用于对两个整数的二进制表示进行按位异或操作。
表达式 9^2 会先计算 2 的值(即 2),然后与 9 进行按位异或操作。按位异或操作会对两个数的每一位进行比较,如果相同则结果为 0,不同则结果为 1。
9 的二进制表示是 1001,2 的二进制表示是 0010。按位异或后的结果是 1011,即十进制的 11。
因此,cout << 9^2 << endl; 会输出 11,而不是 81。

9、小杨今年春节回奶奶家了,奶奶家的数字电视要设置ip地址并接入到WIFI盒子才能收看节目,那这个WIFI盒 子具有路由器的功能。( )

正确答案:正确

根据描述,奶奶家的数字电视能够通过遥控器输入电视剧名称来查找和播放电视剧,这确实表明电视内部运行着某种交互式程序。这种程序能够接收和处理用户的输入,并根据输入执行相应的操作(如搜索和播放电视剧)。

10、任何一个 for 循环都可以转化为等价的 while 循环( )。

正确答案:正确

for 循环和 while 循环在功能上是等价的,这意味着任何一个 for 循环都可以被重写为一个功能相同的 while 循环。for 循环的初始化、条件判断和迭代部分可以分别放在 while 循环之前、条件和循环体内部来实现相同的效果。

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

相似字符串

【问题描述】
对于两个字符串 A和 B,如果 A可以通过删除一个字符,或插入一个字符,或修改一个字符变成B ,那么我们说A和B 是相似的。
比如 apple 可以通过插入一个字符变成 applee ,可以通过删除一个字符变成 appe ,也可以通过修改一个字符 变成 bpple ,因此 apple 和 applee 、 appe 、 bpple 都是相似的。但 applee 并不能通过任意一个操作变成
bpple ,因此它们并不相似。
特别地,完全相同的两个字符串也是相似的。
给定T 组 A, B,请你分别判断他们是否相似。
【输入描述】
第一行一个正整数T 。
接下来T 行,每行两个用空格隔开的字符串A 和 B。
保证T <= 100 ,A , B 的长度不超过 50。保证 A 和 B 只包含小写字母。
【输出描述】
输出 T 行,对于每组A , B ,如果它们相似,则输出 similar ,否则输出 not similar 。
【特别提醒】
在常规程序中,输入、输出时提供提示是好习惯。但在本场考试中,由于系统限定,请不要在输入、输出中附带任
何提示信息。
【样例输入 1】
5
apple applee
apple appe
apple bpple
applee bpple
apple apple
【样例输出 1】
similar
similar
similar
not similar
similar

#include <iostream>  

using namespace std;  
int len1, len2, samelen;

bool same(string a, string b){
	samelen = 0;
	for (int i = 0; i < len2; i++){ // 将不短的字符串删除一个字符, 看是否相同 
		if (len1 != len2){
			string tmp = "";
			for (int j = 0; j < len2; j++){
				if (j != i){
					tmp += b[j];
				}
			}	
			if (a == tmp){
				return true;
			}
		}else{
			if (a[i] == b[i]){
				samelen++;
			}
		}
	}
	if (len1 == len2 && (len1 - samelen <= 1)){
		return true;
	}
	return false;
}

int main() {  
	int n;
	string s1, s2, s;
	cin >> n;
	for (int i = 1; i <= n; i++){
		cin >> s1 >> s2;
		len1 = s1.length();
		len2 = s2.length();
		if (len1 > len2){ // 保证s2是不短的字符串 
			swap(s1, s2);
			swap(len1, len2);
		}
		if (same(s1, s2)){
			cout << "similar\n";
		}else{
			cout << "not similar\n";
		}
		
	} 
    return 0;  
}

做题

【问题描述】
小杨同学为了提高自己的实力制定了做题计划,在第 k 天时,他必须要完成 k 道题,否则他就会偷懒。
小杨同学现在找到了一个题库,一共有 n 套题单,每一套题单中有一定数量的题目。但是他十分挑剔,每套题单他 只会使用一次,每一天也只能使用一套题单里的题目,之后那套题单就会被弃之不用。对于每套题单,他不必完成 题单内所有的题。
那么问题来了,小杨同学最多会做题几天才偷懒呢?
【输入描述】
第一行,1个数为n ,表示有多少套题单。
第二行,n个整数 a 1 , a 2 , . . . , a n a_1, a_2, ..., a_n a1,a2,...,an ,分别表示每套题单有多少道题。
【输出描述】
输出一行,小杨同学偷懒前最多做题天数。
【样例输入 1】
4
3 1 4 1
【样例输出 1】
3
对于全部数据,保证有 1 < = n < = 1 0 6 , 1 < = a i < = 1 0 9 1 <= n <= 10^6, 1 <= a_i <= 10^9 1<=n<=106,1<=ai<=109

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 10;
int main(){
    int n, arr[maxn], start, ans;
    start = 1;
    ans = 0;
    cin >> n;
    // 输入每套题的数量
    for (int i = 1; i <= n; i++){
        cin >> arr[i];
    }
    // 将题目数量从小到大排序,为贪心做准备
    // 冒泡排序TLE
    // sort排序仍然TLE, 优化贪心策略
    // 优化贪心方法: 如果遇到第一个满足条件的提单,则下次循环的时候从当前位置开始循环即可
    sort(arr + 1, arr + n + 1);
    // 贪心, 外层循环代表第几天
    for (int i = 1; i <= n; i++){
        // 遍历每套题的数量
        for (int j = start; j <= n; j++){
            // 如果 第i天  <= 这套题的数量, 就做题, 并将这套题置0, 表示做过了
            if (i <= arr[j]){
                ans++;
                arr[j] = 0;
                start = j + 1;
                break;
            }
        }
    }
    cout << ans;
    return 0;
}
  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青岛少儿编程-王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值