跳转至

前缀和与记忆化

1. 前缀和数组(Prefix Sum)

前缀和是一种 预处理数组区间和 的技巧。 它的作用是:

快速求任意一段连续区间的总和。

如果没有前缀和,每次求区间和都要循环累加,效率低。


2. 前缀和的核心思想

设原数组:

a = [2, 4, 1, 6, 3]

定义前缀和数组 sum[i]

sum[i] = 前 i 个数的总和

即:

sum[0] = 0
sum[1] = 2
sum[2] = 6
sum[3] = 7
sum[4] = 13
sum[5] = 16

3. 区间和公式

要求区间 [l, r] 的和(下标从1开始):

sum[r] - sum[l - 1]

例如求第2到4个数:

4 + 1 + 6 = 11

计算:

sum[4] - sum[1] = 13 - 2 = 11

4. C++ 模板

#include <iostream>
using namespace std;

int main()
{
    int n;
    cin >> n;

    int a[1005], sum[1005];

    sum[0] = 0;

    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sum[i] = sum[i - 1] + a[i];
    }

    int l, r;
    cin >> l >> r;

    cout << sum[r] - sum[l - 1];
}

5. 常见用途

5.1 多次查询区间和

例如:

查询 1~5
查询 3~8
查询 2~9

前缀和非常快。

5.2 二维前缀和

用于矩阵求子矩形和。

5.3 配合枚举优化

很多 O(n²) 题目会用到。

6. 常见错误

6.1 下标混乱

建议统一从 1 开始存数组。

6.2 忘记初始化

sum[0] = 0;

6.3 区间公式写错

正确:

sum[r] - sum[l - 1]

7. 记忆化搜索(Memoization)

记忆化搜索本质是:

递归 + 保存已经算过的答案,避免重复计算。

适合:

  • 递归问题
  • 状态重复出现
  • DFS + DP 类型题目

8. 为什么需要记忆化

例如斐波那契:

f(5)
= f(4) + f(3)

而:

f(4) 又会算 f(3)
f(3) 又被重复算很多次

导致大量重复计算。

9. 核心思想

第一次算:

f(6)

得到结果后存起来:

memo[6] = 8

下次再求 f(6)

直接返回 memo[6]

不用重新递归。


10. 斐波那契模板

#include <iostream>
using namespace std;

long long memo[1005];

long long f(int n)
{
    if(n == 1 || n == 2) return 1;

    if(memo[n]) return memo[n];

    return memo[n] = f(n - 1) + f(n - 2);
}

int main()
{
    int n;
    cin >> n;

    cout << f(n);
}

11. 记忆化搜索常见用途

11.1 斐波那契数列

经典入门题。

11.2 网格走路问题

(1,1)(n,m) 有多少走法。

11.3 最长路径问题

DFS 搜索时记录答案。

11.4 状态压缩搜索

高阶题常见。

12. 前缀和 vs 记忆化

技巧 本质 用途
前缀和 预处理累计信息 快速求区间
记忆化 保存递归结果 避免重复计算

13. 如何选择

如果题目是:

连续区间求和

用前缀和。

递归重复状态

用记忆化。


14. 一句话理解

前缀和

提前把前面的和算好,后面直接减。

记忆化

算过一次的结果记下来,下次直接拿。