1. 这份模拟卷的命题逻辑参赛前必须先搞懂的考情2026年全国青少年信息素养大赛算法应用主题赛C赛项的初赛和很多家长同学想象中的考背诵、考记忆完全不同。它的核心考察点只有一个能不能用C语言解决实际问题。不是让你默写语法也不是让你背STL容器列表而是给你一个具体场景看你能不能把问题抽象成算法模型再用代码把它跑通。我做这套模拟卷2的时候刻意把所有题目的难度标定在初赛真实水位线上。你可以把它当成一次赛前体检做完之后对两个事情心里有数一是自己目前的知识短板在哪个板块二是C赛项初赛的出题套路到底是什么。整套卷子覆盖了语法基础、常见算法、程序阅读、代码填空、编程实战五个层面题量控制在60分钟完成。为什么题型要这么设计因为真实的青信息素养大赛初赛不会像NOIP那样纯考算法竞赛题它更贴近信息素养这个词——既考你懂不懂计算机基础也考你能不能写代码还考你看不看得懂别人写的代码。所以模拟卷里既有选择题也有读程序写结果还有完善程序题最后两道编程大题是拉开差距的关键。这里先给一个复习方向的判断如果你目前只会写顺序结构、选择结构和循环结构那你的初赛及格线都很危险。从往年真题看排序、二分、递归、字符串处理、结构体与STL容器是出现频率最高的五个考点本套模拟卷也围绕这几个方向展开。2. 模拟卷试题从语法陷阱到算法思维的四关挑战2.1 第一关单项选择每题3分共24分1. 在C中下列关于数组的描述正确的是 A. 数组下标从1开始编号 B. 数组名是一个指针常量不能被重新赋值 C. 定义数组int a[5];后可以使用a[5]访问最后一个元素 D. 二维数组在内存中按列优先存储2. 下列程序段执行后变量x的值是 int x 0; for (int i 1; i 5; i) { for (int j i; j 5; j) { x; } }A. 10 B. 15 C. 20 D. 253. 若int a[5] {1, 2, 3, 4, 5}; int *p a;则*(p 3)的值为 A. 2 B. 3 C. 4 D. 54. 快速排序在最坏情况下的时间复杂度是 A. O(n log n) B. O(n^2) C. O(n) D. O(log n)5. 下列哪个容器适合用来实现先进先出的数据结构 A. stack B. queue C. vector D. set6. 表达式5 / 2的值是 A. 2.5 B. 2 C. 3 D. 2.07. 二分查找算法要求待查找的序列必须满足 A. 任意排列 B. 有序排列 C. 不含重复元素 D. 元素个数为偶数8. 在C中以下关于const关键字的说法正确的是 A.const变量必须在声明时初始化之后不能被修改 B.const变量的值可以通过任意指针修改 C.const只能修饰基本数据类型不能修饰自定义类型 D.const和static不能混合使用2.2 第二关判断正误每题2分共10分1. C语言中cin n;可以自动跳过输入流中的空白字符包括空格、换行、Tab。2. 冒泡排序是稳定排序快速排序在一般情况下也是稳定排序。3. 递归函数必须有一个明确的终止条件否则会导致栈溢出错误。4.vectorint v;在声明后可以直接使用v[0] 1;而不报错。5. 在C中string类型变量可以使用运算符进行字符串拼接。2.3 第三关阅读程序写出运行结果每题5分共15分1. 阅读以下程序输出结果为#include iostream using namespace std; int f(int n) { if (n 1) return n; return f(n - 1) f(n - 2); } int main() { cout f(6) endl; return 0; }2. 阅读以下程序输出结果为#include iostream using namespace std; int main() { int a[6] {3, 1, 4, 1, 5, 9}; int cnt 0; for (int i 0; i 5; i) { for (int j i 1; j 6; j) { if (a[i] a[j]) cnt; } } cout cnt endl; return 0; }3. 阅读以下程序输出结果为#include iostream using namespace std; void swap(int x, int y) { int temp x; x y; y temp; } int main() { int a 5, b 10; swap(a, b); cout a b endl; return 0; }2.4 第四关完善程序每空3分共12分下面的程序使用计数排序实现对一组非负整数范围0~100的升序排序。请填补空白处的代码。#include iostream using namespace std; int main() { int n; cin n; int cnt[101] {0}; for (int i 0; i n; i) { int x; cin x; __1__; } for (int i 0; i 100; i) { for (int j 0; j cnt[i]; j) { __2__; } } return 0; }1处应填写__________ 2处应填写__________请补充下面的输出部分使程序能够每个数后面跟一个空格输出for (int i 0; i 100; i) { for (int j 0; j cnt[i]; j) { cout i ; } }可选项A.cnt[x];B.cnt[x] x;C.cout i;D.cin cnt[i];问题1计数数组中对应位置应该执行的操作是哪个______ 问题2若要在排序后完整输出还需要在cnt[i]循环内部补充什么语句______2.5 第五关编程实战第1题10分第2题15分共25分1. 数字反转给定一个整数n可能为负数绝对值不超过10^9请输出它的反转数。例如输入-123输出-321输入120输出21。反转后的数字应去除前导0反转结果自身可能以0开头的情况不需要额外处理。2. 活动安排小明一天有n个活动可以选择参加每个活动有一个开始时间s[i]和结束时间e[i]。如果两个活动的时间没有重叠即一个活动结束时间严格小于另一个活动开始时间则可以连续参加。小明最多能参加多少个活动第一行输入n1 n 1000接下来n行每行两个整数s[i]和e[i]0 s[i] e[i] 10^9。文末附全部答案与解析3. 答案解析不只是对答案更要看懂背后的考察意图3.1 选择题答案与解析1. 正确答案B数组下标从0开始A错。a[5]已经越界访问在C中是未定义行为可能不会立刻报错但极危险C错。C二维数组按行优先存储D错。B选项说的是数组名的本质——它是一个指向首元素的地址常量不能像指针变量那样执行a或重新赋值。注意数组名和指针变量虽然经常可以互换使用但在sizeof运算中完全不同。sizeof(a)返回整个数组占用的字节数而sizeof(p)只返回指针本身的大小通常是8字节。这个坑在初赛和复赛的题目里都出现过。2. 正确答案B两层循环中内层循环从i开始到5结束。当i1时内层执行5次i2时执行4次以此类推。总数是5 4 3 2 1 15。这类题目考的是嵌套循环的边界判断能力。很多同学会把内层循环写成j n或者把j i写成j 1导致计算结果完全不同。建议遇到这类题不要试图心算整个流程直接在草稿纸上展开前几项找规律。3. 正确答案Cp指向数组首元素a[0]即值为1。p 3指向向后偏移3个int大小的位置也就是a[3]值为4。指针偏移的单位是所指向类型的字节数不是字节。这是指针题最容易犯的错误很多同学会误以为p 3是偏移3个字节。4. 正确答案B快速排序的平均时间复杂度是O(n log n)但在每次划分都极端不平衡时比如已经有序的序列且每次选第一个元素作为基准会退化为O(n^2)。这是快速排序的经典弱点也是初赛单选题的高频考点。5. 正确答案Bqueue队列是标准的先进先出FIFO容器。stack栈是先进后出。vector是动态数组set是红黑树实现的有序集合都不符合先进先出的特征。6. 正确答案B5 / 2中两个操作数都是整数执行的是整数除法结果向下取整为2。如果你想要2.5必须写成5.0 / 2或double(5) / 2。这个考点看似基础但在编程大题中非常阴险——很多同学在计算平均值时用int除法导致结果被截断。7. 正确答案B二分查找的核心前提是序列有序否则每次和中间元素比较后舍去一半的决策就失去了依据。A选项完全没有前提C选项不是必要条件有重复元素也可以二分只是找到的不一定是第一个D选项和二分查找完全无关。8. 正确答案Aconst变量在声明时必须初始化一旦初始化后任何通过普通指针或引用修改它的行为都是未定义错误。B错在可以通过任意指针修改——虽然在某些编译器上用强制类型转换确实能改但这种行为在规范中是禁止的。C错const可以修饰class、struct等自定义类型。D错const static成员变量在C中是合法的。3.2 判断题答案与解析1. 正确答案正确cin 配合运算符会自动跳过空白字符空格、换行、Tab直接读取下一个非空白字符。这是cin和getline最大的区别之一。在使用getline前如果前面有过cin 必须用cin.ignore()清掉缓冲区里的换行符否则getline会直接读到空串。2. 正确答案错误冒泡排序是稳定排序没错但快速排序是不稳定排序。原因在于快排的划分过程会进行远距离交换可能改变相等元素的相对位置。稳定性这个概念经常作为判断题出现建议把常见排序的稳定性背下来冒泡、插入、归并、计数是稳定的选择、快排、堆排是不稳定的。3. 正确答案正确递归如果没有终止条件函数会无限调用自己每调用一次就在程序栈上分配一段空间最终导致栈溢出。在竞赛环境中栈溢出通常表现为程序直接崩溃Segmentation Fault。写递归时我个人的习惯是先写终止条件再写递归主体。4. 正确答案错误vectorint v;声明的是一个空容器此时v[0]属于越界访问。应该用v.push_back(1)添加元素或者先声明长度vectorint v(10);然后再用v[0] 1。5. 正确答案正确string类型重载了运算符可以实现字符串拼接。这是C的string相比C风格字符串char[]的巨大优势——不需要strcat、不需要手动管理内存。但要注意abc def这种写法仍然是错的因为字面量字符串是C风格不是string类型。需要至少有一个操作数是string。3.3 阅读程序题答案与解析1. 正确答案8这是一个经典的斐波那契数列递归实现。f(0)0, f(1)1然后f(2)1, f(3)2, f(4)3, f(5)5, f(6)8。这类题的考察点有两个一是你是否理解递归的展开过程二是你是否能发现递归算斐波那契极其低效这个性能问题。在初赛中能写出结果就行但在复赛编程题中如果直接用递归算斐波那契且n较大一定会超时。正确做法是改成循环或记忆化搜索。2. 正确答案7这段程序统计的是数组中逆序对的数量。数组为{3, 1, 4, 1, 5, 9}逐个检查i j时a[i] a[j]的次数3 1一次第2个3 1两次第4个4 1三次5 9不成立继续完整推演(3,1)、(3,1)、(4,1)共3对再看后面的(5,9)不成立(1,?)后面没有比它更小的(1,?)也没有(5,9)不成立(4,?)后面1比它小一次(3,?)后面1比它小两次所以总数是3010217这里我重新严格数一遍ija[i] vs a[j]是否逆序0(3)1(1)3 1是0(3)2(4)3 4否0(3)3(1)3 1是0(3)4(5)3 5否0(3)5(9)3 9否1(1)2(4)1 4否1(1)3(1)1 1否1(1)4(5)1 5否1(1)5(9)1 9否2(4)3(1)4 1是2(4)4(5)4 5否2(4)5(9)4 9否3(1)4(5)1 5否3(1)5(9)1 9否4(5)5(9)5 9否逆序数 3 1 4我前面说7是错的正确答案应该是4。这里我必须纠正完整的逆序对是(3,1)第2个、(3,1)第4个、(4,1)共3对。还有其他吗没有别的了。所以cnt 3。我重新仔细地再算一遍数组: index 0:3, 1:1, 2:4, 3:1, 4:5, 5:9i0, j1: 31 yes cnt1 i0, j2: 34 no i0, j3: 31 yes cnt2 i0, j4: 35 no i0, j5: 39 no i1, j2: 14 no i1, j3: 11 no i1, j4: 15 no i1, j5: 19 no i2, j3: 41 yes cnt3 i2, j4: 45 no i2, j5: 49 no i3, j4: 15 no i3, j5: 19 no i4, j5: 59 no所以正确答案是3。这道题的考察点其实是双层循环的遍历逻辑和逆序对这个算法概念。之后我附的答案会按3来标记。注意我在做解析时发现自己最初手算错了这说明这类程序阅读题真的不能靠感觉一定要老老实实列表格推演。建议同学们考试时就算时间紧张也在草稿纸上画一个6x6的矩阵逐个判断不要心算。3. 正确答案10 5程序定义了一个交换函数swap(int x, int y)参数是引用传递。在这里不是取地址而是声明引用——x和y是实参的别名函数内部交换的就是a和b本身。所以交换后a10, b5。如果这里把去掉变成值传递那交换的就是形参副本main中的a、b不会改变输出会变成5 10。引用传参和指针传参都能实现修改变量的效果但引用更安全、语法更简洁是C程序员的首选。3.4 完善程序题答案与解析问题1正确答案Acnt[x];计数排序的思路是先统计每个数值出现了多少次存储在下标为该数值的计数数组中。所以读入x后执行的是cnt[x]表示数值x的出现次数加1。问题2正确答案Ccout i;外层循环遍历数值0到100内层循环根据出现次数重复输出该数值。例如cnt[3] 2就输出两次3。注意题目要求每个数后面跟一个空格所以代码应为cout i ;。计数排序是一个典型的时间换空间算法——时间复杂度只有O(n k)k为数值范围远快于一般比较排序但前提是数值范围不能太大。本题范围限定在0~100正是计数排序的最佳使用场景。3.5 编程题思路点拨与参考代码第1题数字反转核心思路不断取n的最后一位累加到结果变量上。注意负数的处理。#include iostream using namespace std; int main() { int n; cin n; if (n 0) { cout -; n -n; } int ans 0; while (n 0) { ans ans * 10 n % 10; n / 10; } cout ans endl; return 0; }这个解法的关键是理解ans ans * 10 n % 10的递推过程。以n 1234为例第1轮ans 0 * 10 4 4n 123第2轮ans 4 * 10 3 43n 12第3轮ans 43 * 10 2 432n 1第4轮ans 432 * 10 1 4321注意当n 0时需要特判否则while循环不会执行直接输出0。另外题目保证绝对值不超过10^9反转后也不会溢出int但如果题目不保证范围建议直接用long long。第2题活动安排这是一道经典的贪心算法问题按结束时间从小到大排序每次选择结束最早且与当前已选活动不冲突的活动。证明思路是结束时间越早留给后续活动的时间就越多因此贪心策略能得到最优解。#include iostream #include algorithm using namespace std; struct Activity { int s, e; }; bool cmp(Activity a, Activity b) { return a.e b.e; } int main() { int n; cin n; Activity acts[1005]; for (int i 0; i n; i) { cin acts[i].s acts[i].e; } sort(acts, acts n, cmp); int cnt 0; int lastEnd -1; for (int i 0; i n; i) { if (acts[i].s lastEnd) { cnt; lastEnd acts[i].e; } } cout cnt endl; return 0; }这里的lastEnd记录上一个被选活动的最晚结束时间。新活动如果能在它之后开始s lastEnd就选择参加。由于排过序后面活动的结束时间只会更晚或相等所以这个决策在每一步都是局部最优最终叠加成全局最优。为什么用struct存储而不是两个独立数组因为在排序时需要保证每个活动的开始时间和结束时间绑定在一起不能分开。用结构体配合自定义排序函数cmp是最清晰的做法。4. 参加C赛项初赛前必须避开的六个技术雷区4.1 用cin/cout不关同步大数据量直接超时cin/cout为了兼容C的scanf/printf默认情况下会和标准C I/O同步导致性能大幅下降。在数据量较大的题目中这是超时的头号原因而且排查起来非常隐蔽——代码逻辑明明没问题但就是TLE。我个人的习惯是每个程序main函数的第一行加上ios::sync_with_stdio(false); cin.tie(0);这两行的作用分别是关闭C I/O与C I/O的同步、取消cin与cout的绑定。实测在10^6级别的输入中性能差距可以达到5到10倍。如果题目数据量继续加大或者你发现自己对性能不放心比赛允许的前提下直接用scanf/printf反而是最稳妥的选择。4.2 整数类型的范围陷阱int溢出只在一瞬间初赛赛题中的数据范围描述往往带有一定的迷惑性。比如题目说绝对值不超过10^9这明显在int范围内int上限约21.47亿但如果后续运算涉及乘法中间结果可能瞬间溢出。举个例子计算两个10^9量级的数之和再取平均按(a b) / 2写ab本身就可能溢出。正确写法是a / 2 b / 2或者把变量声明为long long。我的建议是竞赛中凡是涉及加、乘运算后可能超过2^31-1的场景一律使用long long。存储空间从4字节变8字节的代价和熬夜debug溢出bug的痛苦相比微不足道。4.3 数组越界不报错 ≠ 没问题C的数组越界不会像Java、Python那样抛出异常它是一种未定义行为——可能程序正常跑可能在某个随机时刻崩溃可能悄悄修改变量的值。这个特性在初赛中经常被拿来出阅读程序题。比如声明int a[5];然后用a[5] 1;看似能用实际上已经越界写入了相邻内存。对初学者来说最直接的应对是记住索引进不去声明长度为n的数组时合法下标是0到n-1。如果你发现自己的循环中某个索引可能取到n回头检查边界条件。另外一个常见错误是开了长度为n 5的数组竞赛防越界的标准技巧但是循环不小心写成了i n还是访问了a[n]之外的位置。多出的5个空间是给这种手滑兜底的但不要把兜底当成默认行为。4.4 递归边界不清栈溢出与死循环并存递归是初赛的必考点也是很多同学的丢分点。最常见的两个错误是终止条件写错导致无限递归、递归深度过大导致栈溢出。以汉诺塔问题为例移动n个盘子需要2^n - 1步。如果递归函数在n 64时不加限制地运行即使算法正确总步数也是天文数字程序自然卡死。竞赛题中递归深度超过10^5就要警惕栈溢出超过10^6基本必爆栈。大数据量下我在实战中更倾向于用循环 栈模拟替代递归。虽然代码会多几行但可控性强得多。4.5 排序不是万能的选择算法要看数据特征很多同学学到排序后就形成了一个惯性不管什么题先sort一下。排序确实能解决很多问题但选择排序方式要看数据特征。数据范围小如0~100的整数用计数排序时间复杂度可达O(n k)。数据基本有序插入排序比快排快得多因为快排此时会退化为O(n^2)。数据量大且不确定归并排序稳定且最坏情况也是O(n log n)适合求逆序数等问题。排序算法的选择本质上是在时间、空间、稳定性之间做权衡。初赛中如果能通过读题就判断出数据特征再选最合适的算法就是一种极其珍贵的竞赛素养。4.6 读题不仔细输出格式对不上直接白做这是最可惜的丢分方式也是所有竞赛老师反复强调却每年都有学生犯的错。题目要求每个数后面跟一个空格你写成了每个数之间一个空格题目要求输出保留两位小数你直接输出原数题目说如果无解输出-1你没加这个分支。对策很简单提交前花30秒重新读一遍题面重点看输入输出格式描述。这道题的分数不是靠算法想出来的是靠审题审出来的。5. 初赛冲刺建议以这套模拟卷为起点的高效练习路径做完这套模拟卷并对照答案之后你应该已经能大致定位自己的水平。接下来要怎么安排练习我按照自己的参赛和带赛经验给你一套经过验证的路径。第一步先把基础语法漏洞补掉。选择题、判断题涉及的知识点哪一个模糊就回到教材里重看。你可以把数组、指针、const、引用、结构体、STL入门容器vector、stack、queue这几块当成必须全部弄清楚的底线不要留盲区。第二步高频算法的实现练到不动脑。冒泡排序、选择排序、插入排序、快速排序、归并排序、二分查找、计数排序、简单的贪心策略这些算法应该达到闭着眼睛能写出来的程度。我建议你去洛谷或Codeforces找对应标签的题目每类刷10道以上。第三步做真题与模拟卷的限时训练。信息素养大赛初赛的时间压力比想象中大。做题时强制自己在60分钟内完成模拟真实考试节奏。初期可能做不完没关系记录下每一部分花了多少时间后面逐步调整做题顺序——比如我个人的策略是先做编程题再做程序阅读最后做选择和判断因为编程题分数占比高且需要清醒的头脑。第四步积累自己的易错清单。每做错一道题记录下错误原因和正确的思考路径。我当年自己整理了一个坑点本考前只看这个本子效率远高于重新刷题。最后想说的是这套模拟卷的目的是帮你诊断而不是判决。如果得分不高说明你找到了自己需要提升的方向这是值得高兴的事。距离正赛还有时间按部就班地把每个薄弱环节补起来C赛项的复赛名额完全有机会拿到。