GESP2026年9月认证C++一级( 第三部分编程题(2、棋盘上的奖赏))精讲



下面我们来讲解这份 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:🌾

总麦子 ans:0

六、然后开始一个一个格子处理

假设:

复制代码
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 下一格 f
1 1 1 2
2 2 3 4
3 4 7 8
4 8 15 16
5 16 31 32

你会发现一个非常漂亮的规律:

复制代码
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个错误

❌ 错误1:f从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;

记住:

先把这一格收进仓库,再准备下一格。


❌ 错误4:ans没有初始化

虽然在这份参考程序中:

复制代码
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 一开始总数为0
ans += f 把当前格麦子加入总数
f *= 2 下一格是当前格2倍
printf("%lld") 输出long long

这道题最值得孩子掌握的并不是"棋盘麦子"这个故事,而是一个非常通用的累加器模型:

用一个变量记录"当前值",用另一个变量记录"累计答案",每循环一次更新当前值,再累计到答案中。


相关推荐
努力努力再努力wz1 小时前
【CUDA 入门系列】核函数与线程模型:一文理清 Grid、Block、dim3、内置变量与全局索引
c++·架构
ShineWinsu1 小时前
对于Redis:ZSet类型的解析
数据库·c++·redis·缓存·面试·有序集合·zset
All for pursuit.1 小时前
【回溯-5】78.子集
数据结构·c++·算法·leetcode
辛苦才能1 小时前
C++ 红黑树(上):五条规则背后的近似平衡与插入的三类情况
开发语言·c++
by209992 小时前
学会使用 std::string 类,并理解其内部是如何管理字符串的详细阐述(下)
c++·经验分享·笔记·字符串·类和对象·string
.道阻且长.2 小时前
C++11 :新的类功能,lambda,包装器
开发语言·c++·后端
liulilittle2 小时前
短期内不存在通用 AI 工作流魔法
大数据·开发语言·c++·人工智能·llm·agent·tools
_wxd6662 小时前
C++STL map与set
数据结构·c++
别动我齐刘海2 小时前
简历技术栈全面复习总结
c++·人工智能·深度学习·学习·tcp/ip·算法·rpc