
每一届蓝桥杯省赛结束之后都有大量同学来找我聊同一个问题“真题到底该怎么刷我现在开始备赛是先做题库还是先做真题”我的答案一直没变过真题永远是效率最高的切入点。第十六届省赛题目我也在持续整理中目前已经回收并手推了一部分题这篇文章先分享整卷结构、已收录题目的解题思路、以及我认为最关键的备赛方法。后面更新的题目我会在文末说明你可以当作一份“带注释的题解草稿”来看。1. 第十六届省赛真题的整体盘子难度、分值、题型三重观察1.1 为什么蓝桥杯真题是“押题率”最高的资源先说一个很多新手没意识到的事实蓝桥杯的出题风格虽然每年都有微调但核心的考点谱系非常稳定。我统计了近五年的省赛真题C/C 组和 Java 组的题目分布在“模拟与数学”“搜索与图论”“动态规划与贪心”“字符串与数据结构”“数论与组合计数”这几大板块的比例几乎没有大起大落。这说明什么说明你只要把真题吃透就相当于把命题人的题库给“预判”了。第十六届省赛的整卷延续了这一规律但有两个明显变化值得关注第一题面变长场景描述更复杂。往年一道模拟题可能两三行就说清楚规则今年有几道题花了大段文字去描述“物流路径”“数据清洗”之类的业务背景。这意味着读题能力本身正在成为考察点而不是单纯的算法能力。第二综合性更强。前几年省赛的压轴题常常是“单独的大搜索”或者“明显的状态压缩DP”今年我看到的题目中有不少是“二分 图论”“前缀和 思维转化”这类组合型考法。这对只背模板、不理解原理的参赛者是致命的。1.2 分值分布与答题策略推导蓝桥杯省赛的题量常规情况下是10道题其中前几道是填空题只要结果不要过程后几道是程序设计题需要提交完整代码按测试点给分。结合第十六届的情况我建议的答题时间分配是这样的题号区间题目类型建议用时策略第1-2题填空题/简单编程20分钟内必须全对这是保底分第3-5题思维基础算法40-50分钟争取AC 2-3道第6-8题中等算法题50-70分钟目标拿部分分优化测试点覆盖率第9-10题压轴题剩余时间宁可暴力拿前30%的分也别空着很多人有个误区觉得压轴题写不出来就等于没戏。实际操作中蓝桥杯是按测试点给分的压轴题即使只跑过小数据也能拿到可观的分数。我见过的选手中有不少是靠“暴力 部分优化”挤进省一的这绝对是一条值得认真对待的路线。1.3 “更新中”版本的真题该怎样定位既然题解还在更新你手里拿到的可能是一份不完整的题目集。这在备赛阶段反而是好事——你可以先拿已经更新的部分做深度梳理剩下的保持关注、定期回看。我会在后面的章节详细说如何用这种“半成品资源”做训练而不是干等完整版。2. 已收录真题的代码思路与踩坑记录这里挑几道我已经整理完的题按“题干压缩 思路演进 代码骨架 踩坑点”的方式呈现。题目描述我会转述核心逻辑具体的完整原题以官方发布为准。2.1 填空第一题进制转换与取模陷阱这类题基本是老兵新传。第十六届又考了“给定一个进制规则求某一大数的某一位或者某几位”。表面上是暴力模拟题实际上考的是进位原理和字符串处理。我看到这道题的第一反应是直接按进制换算公式展开在数组里维护各位数字然后逐位相加。但真上手就会发现一个隐藏问题题目给的数据范围可能达到10^1000级别任何整型类型都存不下必须用字符串或者数组模拟手算。我的代码骨架如下#include bits/stdc.h using namespace std; int main() { string a, b; cin a b; // 将字符串转为数组逆序存储 vectorint A(a.size()), B(b.size()); for(int i 0; i a.size(); i) A[a.size()-1-i] a[i]-0; for(int i 0; i b.size(); i) B[b.size()-1-i] b[i]-0; // 高精度加法注意进位 int len max(a.size(), b.size()) 1; vectorint C(len, 0); int carry 0; for(int i 0; i len; i) { int av i A.size() ? A[i] : 0; int bv i B.size() ? B[i] : 0; int sum av bv carry; C[i] sum % 10; carry sum / 10; } // 去除前导零后输出 int pos len - 1; while(pos 0 C[pos] 0) pos--; for(int i pos; i 0; i--) cout C[i]; return 0; }这里的核心坑点有三个一个是字符串与数组的下标映射。很多人习惯了从低位到高位存储结果进位时忘记处理最高位溢出导致答案少一位。二是输入可能带前导零我见过有同学直接stoi转成整型一测大数据直接爆。三是填空题只需要最终答案所以手算打草稿时也别忘了用程序验算一遍填空题错了整题零分比程序题更残酷。2.2 程序设计题模拟物流配送的最短时间BFS 变形今年的模拟题比往年“有重工业味”。题干大意是在一个网格地图上给定多个配送点和一些障碍物求从起点出发遍历所有配送点并返回的最短时间。这道题表面看像旅行商问题数据范围如果大了确实要状压DP但第十六届的约束条件给得很仁慈——配送点的数量极少不超过5个。这种情况下根本不需要想复杂了直接用 BFS 预处理配送点两两之间的距离再对配送顺序做全排列暴力求解即可。这也是我反复强调的一个原则先看数据范围再决定算法。#include bits/stdc.h using namespace std; const int dx[] {1, -1, 0, 0}; const int dy[] {0, 0, 1, -1}; int n, m; vectorstring grid; int dist[10][10]; // 配送点之间的距离 struct Node { int x, y; }; int bfs(Node start, Node end) { vectorvectorint d(n, vectorint(m, -1)); queueNode q; q.push(start); d[start.x][start.y] 0; while(!q.empty()) { Node cur q.front(); q.pop(); if(cur.x end.x cur.y end.y) return d[cur.x][cur.y]; for(int i 0; i 4; i) { int nx cur.x dx[i], ny cur.y dy[i]; if(nx 0 || nx n || ny 0 || ny m) continue; if(grid[nx][ny] #) continue; if(d[nx][ny] ! -1) continue; d[nx][ny] d[cur.x][cur.y] 1; q.push({nx, ny}); } } return -1; } int main() { // 读入 n, m, grid // 收集起点和配送点位置 vectorNode sites; // sites[0] 为起点其余为配送点 int k sites.size(); for(int i 0; i k; i) for(int j i1; j k; j) dist[i][j] dist[j][i] bfs(sites[i], sites[j]); // 对配送顺序枚举全排列 vectorint order; for(int i 1; i k; i) order.push_back(i); int ans INT_MAX; do { int cur dist[0][order[0]]; for(int i 0; i1 order.size(); i) cur dist[order[i]][order[i1]]; cur dist[order.back()][0]; ans min(ans, cur); } while(next_permutation(order.begin(), order.end())); cout ans endl; return 0; }这道题最值得说的不是BFS本身而是状态建模。很多人一看到“多个点 最短 遍历”就直接去写搜索树上带着“已访问集合”的状态代码一写就是一百多行跑起来还超时。其实只要意识到配送点一共就5个全排列5!120种顺序哪怕每个组合都跑一遍BFS都完全来得及。顺带提一个老生常谈但每年都有人犯的错next_permutation只能正确枚举升序序列的全排列如果你没有先把order排序后面你会漏掉整整一半的排列组合。这个bug隐蔽到什么程度你测试小样例可能全对但一提交就WA而且大概率找不出原因。2.3 程序设计题山峰数组专项单调栈与贡献法今年的中等题里有一道让我印象很深大意是求数组中每个元素“能看见的山峰数量”“能配对的对数”之类的问题。这种题表面是几何感知实际内核是单调栈 贡献法统计。这类题的核心难点在于直接枚举每对元素的时间复杂度是 O(n^2)n若到10^5级别必然超时。解法是利用“单调栈维护右边第一个更高的元素”把问题转化成栈内统计。我给一个典型的求“数组中每个元素右侧第一个更高元素下标”的模板#include bits/stdc.h using namespace std; vectorint monotonicStack(const vectorint arr) { int n arr.size(); vectorint res(n, -1); // 存放右侧第一个更高元素下标 stackint st; for(int i n-1; i 0; i--) { while(!st.empty() arr[st.top()] arr[i]) st.pop(); if(!st.empty()) res[i] st.top(); st.push(i); } return res; }注意这里while循环的条件是代表我们要找的是严格更高的元素。如果你在这里用那么相等高度的山峰也会被算进来导致答案整体偏大——这种bug在逻辑上特别难察觉因为测试样例不仔细根本看不出来。如果你想深入理解单调栈的哲学可以把它想成“每个元素入栈一次、出栈一次”总复杂度是 O(n)。这个思想在很多与“下一个更大/更小元素”相关的题目里都会用到而且常常跟计算面积、统计对数、区间最大值等问题交叉出现是省赛拿奖必须掌握的常规武器。2.4 压轴题区间异或统计前缀异或 哈希表今年压轴题我看到的回忆版本是一道和异或相关的计数题约束条件n到10^5询问区间内满足某异或条件的子区间数量。这道题把我当年第一次见到的时候也卡了很久它的套路非常经典前缀异或 哈希表的相遇问题。核心思路是把数组转换成前缀异或数组pre[i]其中pre[0]0pre[i]pre[i-1]^a[i-1]。那么区间[l, r]的异或值就等于pre[r]^pre[l-1]。如果一个区间要满足某个异或值x那等价于pre[r]^pre[l-1]x进一步可以写成pre[l-1]pre[r]^x。于是问题从“枚举所有区间”变成了“遍历右端点时查表看有多少个左端点符合条件”。#include bits/stdc.h using namespace std; int main() { int n, x; cin n x; vectorint a(n); for(int i 0; i n; i) cin a[i]; vectorint pre(n1, 0); for(int i 0; i n; i) pre[i1] pre[i] ^ a[i]; unordered_mapint, int cnt; cnt[0] 1; long long ans 0; for(int i 1; i n; i) { // 寻找 pre[j] pre[i] ^ x 的前缀数量 int target pre[i] ^ x; ans cnt[target]; cnt[pre[i]]; } cout ans endl; return 0; }这道题看起来短但含金量非常高。它考的不只是异或运算的性质更考你是否能敏锐地把“区间异或和”转化成“两个前缀异或值的关系”。如果你对这类转化不熟即使给你满分模板你也想不到去用它。我自己的经验是对于异或类题目优先想前缀异或。异或的逆运算就是它自己这个性质太优雅了几乎所有区间异或问题都可以从前缀异或入手。3. 把“半成品真题”变成训练弹药100天备赛计划3.1 先做“题型聚类”不要按题号刷真题整理版还在更新中很多人拿到手一不小心就做成“有一道刷一道”这是效率最低的用法。我建议你把已经出现的题目先按知识点重新分组模拟题放一起、搜索题放一起、DP题放一起、数论题放一起。刷的时候不是按顺序做而是按主题逐个击破。比如今天定主题是“搜索”就把真题里的搜索题全部挑出来连同往年类似题一次性做8-10道。这种聚类刷法能帮你在短时间内形成对某类题的条件反射效果远好于撒网式刷题。3.2 黄金三遍刷法每题至少做三遍对于真题我非常推荐“三遍刷法”第一遍拿到题先独立思考半小时想不出就看题解思路然后自己动手把代码写出来。重点是搞懂解题逻辑而不是记住代码。第二遍隔3-7天后把这道题重新做一遍期间不看任何题解。这一遍的最重要价值是暴露你是否真的掌握了而不是“看懂了”。第三遍冲刺期回看题目列表只看题干在脑中快速过一遍思路和复杂度写不出来的就标记为“需要重点突破”。这一遍用来做查漏补缺打开率非常低但是提分效率极高。这个方法看起来占时间实际上省时间。因为它直接消灭了“刷过等于会了”的假象。3.3 从真题反推知识点而不是盲目学很多备赛的同学最大的问题不是不努力而是不会规划。今天看一点图论明天看一点数论跟刷短视频一样没有章法。我的建议是让真题当你的课程大纲。把目前更新的真题逐题摊开标注每一题背后关联的知识点然后把它们整理成一张清单。这个清单比任何一本算法书的前言都更贴合蓝桥杯省赛。清单上出现的知识点优先学透没有出现的可以暂缓。举我自己整理的一个例子第十六届已更新的几道题涉及“高精度”、“BFS/DFS”、“单调栈/单调队列”、“前缀异或与哈希”、“快速幂”。那么我接下来一周的学习重点就定为这五个方向每个方向找10道题做配套训练。这样一来每一次刷题都有明确的靶向就不会出现“什么都会一点但什么都不精”的情况。3.4 利用“更新中”的边角时间差题目还在陆续整理这意味着什么意味着你可以利用这段时间差主动去搜索去年或往年同类型题目做预测性训练。比如第十六届的某道题如果它是BFS最短路模型的变体那往年省赛出现的“迷宫最短路”“传送门最短路径”这些题目就更值得做。真题更新一篇你就补一篇的配套训练始终保持“真题在更新功夫在增长”的节奏。有一种情况你一定会遇到题目更新之后你发现自己之前对某道题的理解方向完全错了。这非常正常。不要懊恼这正是真题集“更新中”这个状态带给你的纠错机会等到完整版出来再看反而没有这个主动纠偏的过程。4. 参赛实战中的常见问题与避坑4.1 填空题到底怎么填结果精度与格式填空题只要一个最终数字过程在考卷上看不到。很多选手并不重视填空题觉得分值小其实填空题的正确率往往决定了你省二和省一的差距。填空题最怕两件事一是算对了但填错位数比如题目要求结果取模1e97你填了原始超大数二是忽略题目给的陷阱条件比如“数字之间用逗号分隔”这种格式要求。我建议比赛时每个填空题至少验算两遍。如果时间和环境允许可以用程序跑一遍甚至可以用两种不同思路各写一个小脚本交叉验证结果一致才算过。填空题没有部分分错一个就是整题归零多花三分钟验算绝对是稳赚不赔的投入。4.2 本地能跑、提交就挂环境差异与未定义行为这是每年提问区最活跃的一类问题“我本地明明通过了样例在OJ上就是WA/RE为什么”原因通常是这几类第一本地编译器版本和OJ环境不一致某些 C 写法是老版本编译器过不了的。比如用了#include bits/stdc.h在某些环境不支持或者auto推导的行为不同。虽然蓝桥杯的评测环境普遍支持新版编译器但你不能假设它跟你本地一模一样。第二数组越界问题。本地运行时内存可能正好没被破坏但OJ上栈里下面恰好存了关键变量就越界出错了。这类问题非常恶心只能靠养成“所有遍历都带上边界检查”的习惯来规避。第三long long溢出。很多选手习惯性用int但第6题之后的数据范围就已经允许算到10^9了两个区间长度相乘立刻溢出。今年我就看到不止一个选手在区间计数题里因为int乘法溢出吃大亏。建议只要可能有乘积的操作一律用long long或__int128不要吝啬这么一点内存。4.3 暴力超时怎么办部分分策略的精细操作蓝桥杯给的是部分分这一点真的是给了选手很大的容错空间。但很多选手却没有利用好。我的建议是读每一道题的时候第一遍先想暴力的做法并且在草稿纸上写下暴力的时间复杂度随后看数据范围计算暴力能覆盖到什么程度。如果题目给了多个子任务通常小数据范围对应暴力解法大数据范围对应正解。你至少要写出能通过最小测试点的代码这是底线。举个例子一道题 n10^5要求 O(nlogn) 或 O(n)但你一时想不出正解。此时如果你写的是 O(n^2) 的暴力很可能一个测试点都过不了如果你发现可以用“对所有偶数下标单独处理”之类的偏方先骗过部分小数据那就远远好过空着交白卷。另外也可以利用“特殊情况”骗分数据保证全是正整数、保证无重复元素、保证图是树形结构。这类特殊情况往往对应着简单解法骗到两三个测试点绰绰有余。4.4 比赛时间分配前松后紧是大忌蓝桥杯省赛的时间一般是四五个小时左右。这个时间是够做完的前提是节奏正确。我见过最典型的失败案例是某位同学前两道送分题花了整整一个小时去精雕细琢导致后面几道中档题没有时间写压轴题更是看都没看。送分题的意义在于拿保底分不在于完美优化。别在第一题追求几十毫秒的加速那是几乎没有意义的行为。一个可参考的时间轴前30分钟完成前两道送分或填空题快、稳、准。第30-90分钟主攻中间的3-5道题先把能拿满的分拿完再回头优化。第90-150分钟逐题尝试后面中等偏上的题目索性别执着于满分能骗一个测试点是一个。最后60分钟全卷复查 把还没有任何代码的题至少写个暴力上去。请记得编码能力你平时练得再好上了赛场心态只要不稳前两道送分题都可能写崩。所以平时模拟就要用多组“有坑样例”来训练心理耐受度。4.5 代码风格与调试习惯现场少走弯路还有两点非常朴素但真实的建议。第一变量名尽量见名知意。赛场上一紧张i, j, k, ans, cnt这类变量是最容易混淆的。尤其是多组数据处理时循环变量用完忘清零直接导致连环WA。你可以试试在本地就练习“每组数据处理前先清零变量”的惯性动作。第二善用注释做断点。现场遇到逻辑不对不要只知道一个劲地断点调试。很多比赛环境调试功能并不顺手与其死磕断点不如在关键分支处加输出语句排查中间量。赛后收藏一份带调试输出的模板能让你的现场改动效率提高50%以上。5. 一点训练体会与扩展蓝桥杯的省赛真题更新就是一个“知识图谱”的搭建过程。每年大家追着新题看其实看的不只是题本身而是命题方向的变化。我的体会是2019年到2025年蓝桥杯难度的上升趋势非常明显。从过去“会基础的就能拿省二”到现在“熟练掌握搜索、DP、数论基础才能稳进省一”这条曲线会一直往上走。但我同时也想告诉你一个反直觉的观察真正得高分的人反而不怎么追逐新题怪题他们做的最多的事情是把基础题反复做透。第十六届的压轴题再花哨它的内核依然是前缀异或 哈希这套思想在多少年前的题里就已经出现过了。考场上拼的很少是“我见过这道题”而是“我能不能把见过的套路迁移到陌生场景”。这份真题集还在更新中我在梳理过程中也会陆续补充完整版的解析和代码。你现在看到的部分已经足够支撑一轮有效的备赛训练了。后续更新上来后我的建议是不要直接看答案先把自己的解法写出来再跟我或者其他题解对照分析优劣。这道工序比单纯刷十道新题都要值钱。如果你在备赛路上遇到想不通的题目或者对我的解题思路有不同的看法欢迎随时交流。毕竟比赛这回事一个人走容易迷路多几个人交换想法路会清晰很多。