)精讲)
下面我们来讲解这份2026年9月 CCF-GESP C 一级第三部分编程题第2题——《棋盘上的奖赏》。这道题表面上是在讲一个古老的“国王赏麦子”的故事实际上是在考同学们一个非常重要的编程思想前一个数字是后一个数字的“爸爸”——每次都变成前一个的2倍。所以这道题的核心就是循环 每次乘2 累加。题目给出的样例是输入3输出7输入10输出1023。一、先来听听“麦粒王国”的故事 很久以前古印度有一位国王。有一位聪明的大臣叫西萨他发明了国际象棋。国王非常高兴“你想要什么奖励尽管说”西萨说“我不要金银财宝只要一些麦子。”国王一听“麦子这也太简单了”于是西萨提出了一个非常特别的要求棋盘第1格放1粒第2格放2粒第3格放4粒第4格放8粒……也就是说每一格都是前一格的2倍。题目问前 N 格一共需要多少粒麦子这就是本题。二、先别急着写代码我们把棋盘摆出来假设N 5那么棋盘前5格是第1格1 第2格2 第3格4 第4格8 第5格16我们把它画成 第1格1 第2格2 第3格4 第4格8 第5格16那么总数就是1 2 4 8 16算一算1 2 3 3 4 7 7 8 15 15 16 31所以前5格 31粒三、这道题最重要的两个变量我们不要一上来就写一大堆代码。先问自己程序运行的时候我到底需要记住什么答案只有两个①f表示当前这一格应该放多少粒麦子。②ans表示前面所有格子加起来一共有多少粒麦子。可以想象成两个小盒子┌──────────────┐ │ f │ │ 当前这一格 │ └──────────────┘ ┌──────────────┐ │ ans │ │ 总麦子数量 │ └──────────────┘四、f一开始应该是多少第一格放多少题目说第1格放1粒。所以f 1;非常重要五、ans一开始应该是多少刚开始我们一粒麦子都没有加进去。所以ans 0;于是程序刚开始f 1 ans 0可以画成当前麦子 f 总麦子 ans0六、然后开始一个一个格子处理假设N 5我们需要处理第1格 第2格 第3格 第4格 第5格所以最自然的代码就是for (int i 1; i n; i)翻译成人话从第1格开始一直处理到第N格。七、第一轮第1格现在f 1 ans 0第1格放1所以ans f;相当于ans ans f;于是ans 0 1 1然后准备进入下一格。因为下一格是当前格的2倍f * 2;也就是f f * 2;于是f 1 × 2 2现在当前格2 总数量1八、第二轮第2格现在f 2 ans 1把当前麦子加入总数ans 1 2 3然后f 2 × 2 4现在当前格4 总数量3九、第三轮第3格现在f 4 ans 3加入ans 3 4 7然后f 4 × 2 8十、第四轮第4格现在f 8 ans 7加入ans 7 8 15然后f 8 × 2 16十一、第五轮第5格现在f 16 ans 15加入ans 15 16 31然后f 16 × 2 32循环结束。最终ans 31所以答案31十二、用表格把整个过程看清楚这张表特别重要小朋友考试的时候甚至可以在草稿纸上画出来。棋盘格当前麦子f加入后ans下一格f1112223434784815165163132你会发现一个非常漂亮的规律f 1 → 2 → 4 → 8 → 16 → 32每次×2而ans 0 → 1 → 3 → 7 → 15 → 31每次把当前的f加进去。十三、所以代码就出来了参考程序#include cstdio #include algorithm using namespace std; int n; long long f, ans; int main() { scanf(%d, n); f 1; for (int i 1; i n; i) { ans f; f * 2; } printf(%lld\n, ans); return 0; }十四、我们把程序变成“小学生语言”第1行int n;准备一个盒子n——棋盘有多少格。第2行long long f, ans;准备两个“大盒子”f → 当前格子的麦子 ans → 所有格子的麦子总数这里特别值得注意为什么不用int而使用long long因为麦子增长得太快了十五、为什么麦子数量会“爆炸式增长” 看看第1格1 第2格2 第3格4 第4格8 第5格16 第6格32 第7格64 第8格128 第9格256 第10格512看起来前面还挺正常。但是继续第20格524288再往后第30格536870912再继续第40格549755813888是不是越来越夸张这就是每次 ×2 的可怕威力。十六、int可能装不下怎么办普通int能表示的整数范围是有限的。而这道题的麦子增长得特别快。所以参考程序选择long long可以理解成 一个比int大得多的数字仓库。所以long long f, ans;就是为了让程序能够存放更大的麦子数量。十七、第二个样例N 10题目样例输入 10输出1023我们自己算一下1 2 4 8 16 32 64 128 256 512全部加起来1 2 4 8 16 32 64 128 256 512结果1023所以前10格 1023粒十八、这里其实藏着一个数学规律小朋友如果学过一些数学会发现1 1 2 3 1 2 4 7 1 2 4 8 15 1 2 4 8 16 31答案分别是1 3 7 15 31它们还有一个非常漂亮的规律1 2¹ - 1 3 2² - 1 7 2³ - 1 15 2⁴ - 1 31 2⁵ - 1所以⭐ 前 N 格的麦子总数 2^N - 1例如N 10 2¹⁰ - 1 1024 - 1 1023十九、那为什么我们不直接写2^N - 1这是一个非常好的问题因为对于初学 C 的小朋友来说这道题真正的考点是循环。题目希望我们学会for以及f * 2; ans f;所以不要为了追求“公式”反而忘记了这道题的编程训练目标。而且在 C 中2 ^ n不是数学里的2ⁿ这里的^是按位异或运算。所以千万不能直接写2 ^ n - 1来表示2^n-1。这是初学者非常容易踩的坑。二十、这道题最核心的两句话如果孩子考试时紧张记住下面两句话就够了第一格麦子是1所以f 1。每处理完一格就把当前麦子加进ans然后让f乘2。也就是ans f; f * 2;这两行是整道题的“心脏”。二十一、完整程序逐行讲解版#include cstdio using namespace std; int n; long long f, ans; int main() { // 输入棋盘格数 scanf(%d, n); // 第1格有1粒麦子 f 1; // 从第1格一直处理到第n格 for (int i 1; i n; i) { // 把当前格子的麦子加入总数 ans f; // 下一格是这一格的2倍 f * 2; } // 输出总麦子数 printf(%lld\n, ans); return 0; }二十二、这道题的“程序思维图”把整个程序压缩成一张图输入 N ↓ 第1格有1粒麦子 ↓ f 1 ans 0 ↓ ┌──────────────┐ │ 处理当前格子 │ └──────┬───────┘ ↓ ans f ↓ f * 2 ↓ 还有下一格吗 ↙ ↘ 有 没有 ↓ ↓ 继续 输出ans这其实就是一种非常重要的编程模型“当前状态 → 加入答案 → 更新状态 → 继续下一轮。”以后学习很多算法都会反复看到这种思想。二十三、孩子最容易犯的5个错误❌ 错误1f从0开始错误f 0;如果这样0 → 0 → 0 → 0 → 0永远都是0。正确f 1;因为第一格就是1粒。❌ 错误2忘记f * 2如果写成ans f;却忘记f * 2;那么每一格都是1粒1 1 1 1 ...显然不对。❌ 错误3先乘2再加如果写成f * 2; ans f;第一格就变成2但题目第一格明明是1所以顺序不能乱。正确顺序ans f; f * 2;记住先把这一格收进仓库再准备下一格。❌ 错误4ans没有初始化虽然在这份参考程序中long long f, ans;随后直接ans f;但这里有一个 C 初学者必须特别注意的知识点局部变量如果没有初始化里面可能是一个未知值。因此更稳妥、也更适合初学者理解的写法是long long f 1; long long ans 0;这样我们就明确知道当前麦子 1 总麦子 0❌ 错误5输出格式写错因为ans是long long所以使用printf时printf(%lld, ans);而不是printf(%d, ans);可以记住int → %d long long → %lld二十四、这道题其实是一个“指数增长”启蒙题 这道题特别有意思的地方在于每次只乘2看起来很慢可是连续乘很多次数字会疯狂增长。比如1 2 4 8 16 32 64 128 256 512 1024 2048 4096 ...这也是计算机科学中非常重要的一种增长方式指数增长。所以这道题表面是 国王给麦子。实际上是在告诉孩子“有些数字虽然开始很小但如果不断翻倍很快就会变得巨大。”二十五、最后给孩子一个“麦粒口诀” 这道题可以用一句口诀牢牢记住第一格1粒粮放进去再翻倍每一格都累加最后得到总麦量。代码就是long long f 1; long long ans 0; for (int i 1; i n; i) { ans f; f * 2; } cout ans; 最后总结这道题到底考什么知识点在题目中的作用int n保存棋盘格数long long保存很大的麦子数量for一格一格处理棋盘f 1第一格有1粒ans 0一开始总数为0ans f把当前格麦子加入总数f * 2下一格是当前格2倍printf(%lld)输出long long这道题最值得孩子掌握的并不是“棋盘麦子”这个故事而是一个非常通用的累加器模型用一个变量记录“当前值”用另一个变量记录“累计答案”每循环一次更新当前值再累计到答案中。