C++前缀和解决区间求和查询与开发注意事项
好的,这是一个典型的**前缀和(Prefix Sum)**问题。直接对每次询问都去循环累加会导致 O(n*m) 的时间复杂度,在 n,m 最大为 100000 的情况下会超时。使用前缀和可以将每次查询优化到 O(1),总复杂度 O(n+m)。 下面我将从**思路分析**、**代码实现**、**代码详解**、**进阶与优化**四个方面为你详细讲解。 --- ## 💡 核心思路:前缀和 **前缀和** 是一种预处理技术,它创建一个新的数组 `prefix`,其中 `prefix[i]` 表示原数组前 `i` 个元素的和(从1开始计数)。 - 定义:`prefix[0] = 0` - 递推公式:`prefix[i] = prefix[i-1] + a[i]` - 查询:前 `k-1` 项的和即为 `prefix[k-1]` 这样,每次询问只需 O(1) 时间即可得出答案,非常适合大规模数据。 --- ## 🧑💻 C++ 代码实现 ```cpp #include <iostream> #include <vector> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // --- 1. 读取 n 和 m --- int n, m; cin >> n >> m; // --- 2. 读取原始数组 a(1-indexed 为了方便)--- vector<int> a(n + 1, 0); for (int i = 1; i <= n; ++i) { cin >> a[i]; } // --- 3. 构建前缀和数组 prefix --- vector<long long> prefix(n + 1, 0); // 使用 long long 防止溢出 for (int i = 1; i <= n; ++i) { prefix[i] = prefix[i - 1] + a[i]; } // --- 4. 处理 m 次询问并输出结果 --- int k; for (int i = 0; i < m; ++i) { cin >> k; // 根据题意,需要输出前 k-1 项的和 cout << prefix[k - 1] << '\n'; } return 0; } ``` --- ## 📝 代码逐段详解 ### 1. 加速输入输出 ```cpp ios::sync_with_stdio(false); cin.tie(nullptr); ``` - **作用**:解除 C++ 标准输入输出与 C 标准输入输出(`stdio`)的绑定,并取消 `cin` 与 `cout` 的同步,大幅提升 I/O 速度。 - **注意**:使用后不能再混用 `scanf`/`printf`,也不要使用 `endl`(用 `'\n'` 替代),否则可能引发缓冲问题。 ### 2. 数组大小与索引 ```cpp vector<int> a(n + 1, 0); ``` - 使用 `n+1` 的大小,并且从 `a[1]` 开始存储,这样 `a[1]` 对应第一个数字,符合题目中 `a[1] ~ a[n]` 的描述,也方便前缀和公式的推导。 - `a[0]` 始终为0,作为哨兵值。 ### 3. 前缀和数组 ```cpp vector<long long> prefix(n + 1, 0); ``` - **数据类型**:使用 `long long`(64位),因为 `a[i]` 最大1000,n 最大100000,前 n 项和最大为 `1000 * 100000 = 1e8`,看似 `int` 够用,但使用 `long long` 是一种良好的防止潜在溢出的习惯。 - **递推**:`prefix[i] = prefix[i-1] + a[i]` - `prefix[0] = 0` - `prefix[1] = a[1]` - `prefix[2] = a[1] + a[2]` - ... ### 4. 查询与输出 ```cpp cout << prefix[k - 1] << '\n'; ``` - **注意**:题目要求计算前 `k-1` 项的和,而不是前 `k` 项。输入保证 `2 ≤ k ≤ n+1`,所以 `k-1` 的范围是 `1 ~ n`,不会越界。 --- ## ⚡ 进阶与优化建议 ### 1. 空间优化 如果内存极度敏感,可以不存储原始数组 `a`,而是边读入边构建前缀和,只需一个前缀和数组即可: ```cpp vector<long long> prefix(n + 1, 0); for (int i = 1; i <= n; ++i) { int val; cin >> val; prefix[i] = prefix[i - 1] + val; } ``` ### 2. 使用 `std::partial_sum` C++ 标准库提供了 `std::partial_sum`,可以直接生成前缀和,代码更简洁: ```cpp #include <numeric> vector<long long> prefix(n + 1, 0); partial_sum(a.begin() + 1, a.end(), prefix.begin() + 1); ``` 但要注意 `partial_sum` 返回的迭代器位置。 ### 3. 超大内存与数据流 如果 n 和 m 更大(如 10^6 以上),建议: - 使用 `scanf`/`printf` 进一步提高 I/O 速度。 - 使用 `int64_t` 替代 `long long`(二者通常等价,但 `int64_t` 更明确)。 ### 4. 常见陷阱与错误 | 错误类型 | 错误示例 | 正确做法 | |---|---|---| | 未处理前缀和边界 | `prefix[0]` 未初始化 | 初始化为0 | | 查询时索引错误 | 输出 `prefix[k]` 而非 `prefix[k-1]` | 题目要求前 `k-1` 项 | | 溢出 | 使用 `int` 存储大和 | 使用 `long long` 或 `int64_t` | | 使用 `endl` 导致超时 | `cout << endl` | 使用 `'\n'` | ### 5. 扩展应用场景 前缀和不仅用于简单求和,还能解决多种变体问题: - **二维前缀和**:处理矩阵子矩阵和 - **带修改的前缀和**:配合树状数组(Fenwick Tree)或线段树 - **前缀异或/前缀积**:处理异或、乘积等运算 - **差分数组**:对区间进行批量增减操作 --- ## 📚 学习资源推荐 - **书籍**:《算法竞赛入门经典(第2版)》- 刘汝佳(前缀和、差分章节) - **在线练习**: - [LeetCode 303 - Range Sum Query - Immutable](https://leetcode.com/problems/range-sum-query-immutable/) - [洛谷 P1115 - 最大子段和](https://www.luogu.com.cn/problem/P1115)(前缀和的进阶应用) - **官方文档**:[cppreference.com - std::partial_sum](https://en.cppreference.com/w/cpp/algorithm/partial_sum) --- ## 💬 开发建议 1. **养成良好的 I/O 习惯**:竞赛或高性能场景下,务必使用 `ios::sync_with_stdio(false)` 和 `'\n'`。 2. **索引从1开始**:在处理序列问题时,1-indexed 可以减少边界判断,使代码逻辑更清晰。 3. **数据类型要严谨**:即使当前数据不会溢出,也养成使用 `long long` 的习惯,避免后期修改遗漏。 4. **模块化思考**:将预处理、查询分离成独立函数,提高代码可读性与可维护性。 --- ######[AI写代码神器 | 1747点数解答 | 2026-05-22 19:43:50]
- Python实现:随机录入45位学生四次成绩函数大揭秘(GPT | 477点数解答 | 2024-12-17 17:00:35)381
- Python实现班级45位同学成绩生成、总评计算及分数统计(字节豆包 | 579点数解答 | 2024-12-21 11:55:01)268
- Python实现45位学生四次成绩随机录入及输出(GPT | 441点数解答 | 2024-12-21 21:02:22)271
- Python实战:45位同学成绩生成、总评计算与分数统计揭秘(字节豆包 | 688点数解答 | 2024-12-22 10:14:17)262
- 补全含错误代码:Vue结合Element UI组件实现查询、新增及表格展示功能 ( | 400点数解答 | 2023-12-19 15:20:50)456
- 单线程频繁查ClickHouse致CPU飙升?这些优化方案速看!(DeepSeek | 491点数解答 | 2025-02-13 17:49:54)254
- MySQL:巧用 NOT LIKE 查询字段不包含特定字符串及注意要点 (DeepSeek | 264点数解答 | 2025-02-13 18:25:01)200
- Java:设计圆类与圆柱体类并计算属性及体积表面积(字节豆包 | 470点数解答 | 2024-10-20 10:03:11)205
- Java 实现矩形与长方体类,精准计算底面积与体积(字节豆包 | 319点数解答 | 2024-10-20 10:25:46)311
- Java 实现矩形与长方体类,轻松计算底面积和体积(字节豆包 | 308点数解答 | 2024-10-20 10:34:27)292
- Java 实现矩形与长方体类:计算底面积与体积的完整代码示例(字节豆包 | 306点数解答 | 2024-10-20 18:34:47)290
- 云南 8 日摄影行程表 HTML 代码优化与逻辑注意点揭秘(字节豆包 | 217点数解答 | 2025-03-09 13:19:03)282