std::partial_sum计算的是包含首元素的累积和,即s[i] = a[0]+…+a[i];要获得左闭右开前缀和sum[i] = a[0]+…+a[i−1],需初始化sum[0]=0后对原数组从sum.begin()+1开始partial_sum。

直接说结论: std::partial_sum 是 C++ 标准库中计算前缀和最安全、最通用的方式,但默认行为是“包含自身”的累加(即 a[0], a[0]+a[1], a[0]+a[1]+a[2]…),不是某些算法题里要的“左闭右开前缀和”(如 sum[i] = a[0]+...+a[i-1])。用错会导致越界或逻辑偏移。
std::partial_sum 默认行为到底算什么?
它按迭代器范围逐元素累加,结果写入目标位置 —— 本质就是“原地/指定位置的累积和”,不区分“前缀和数组定义方式”。关键点:
- 输入范围
[first, last),输出从result开始,长度相同 - 第
i个输出值 =*first + *(first+1) + ... + *(first+i)(共i+1项) - 所以输出数组第
0位就是*first,不是0
示例:
std::vector<int> a = {1, 2, 3, 4};
std::vector<int> s(a.size());
std::partial_sum(a.begin(), a.end(), s.begin());
// s == {1, 3, 6, 10} → 这是标准前缀和(含自身)
想得到「sum[i] = a[0] + ... + a[i-1]」怎么办?
这是很多 DP 或区间查询(如 [l, r) 求和)需要的“左闭右开”前缀和,std::partial_sum 不能直接生成,但可以低成本构造:
立即学习“C++免费学习笔记(深入)”;
- 手动在开头补一个
0,再对{0} + a调用std::partial_sum - 或者更高效:先 resize 目标容器为
a.size() + 1,设s[0] = 0,再对a做 partial_sum 到s.begin() + 1
推荐写法:
std::vector<int> a = {1, 2, 3, 4};
std::vector<int> s(a.size() + 1);
s[0] = 0;
std::partial_sum(a.begin(), a.end(), s.begin() + 1);
// s == {0, 1, 3, 6, 10} → sum[r] - sum[l] 即 [l, r) 区间和
和手写 for 循环比,有啥实际差别?
性能几乎没区别(现代编译器会把简单循环向量化),但 std::partial_sum 的优势在语义明确和泛型安全:
- 支持任意迭代器类型(
std::list、自定义流迭代器等),手写 for 容易漏掉++it或边界 - 可传入自定义二元操作符,比如用
std::multiplies做前缀积:std::partial_sum(a.begin(), a.end(), s.begin(), std::multiplies{}) - 输入输出范围重叠时(如原地计算),
std::partial_sum明确保证行为合法;手写 if 不小心就用了未更新的旧值
坑点:别传 std::vector::end() 当输出起点——它不是有效写入地址,会 UB。
数组 vs vector:用 raw array 怎么调?
一样可用,但要注意指针算术和生命周期:
- 输入必须是
T*,输出也必须是可写的T* - 确保输出空间足够(至少和输入长度相等,或 +1)
- 不要对栈数组用
std::partial_sum后还访问越界索引
例子:
int a[] = {1, 2, 3};
int s[4]; // 多留一位放 0
s[0] = 0;
std::partial_sum(a, a + 3, s + 1); // a+3 是 end,s+1 是起始写入点
// s == {0, 1, 3, 6}
最容易被忽略的是:前缀和是否需要 long long 防溢出 —— std::partial_sum 不做类型推导升级,输入是 int,溢出就真溢出。别只盯着函数怎么调,先看数据范围。


















