题目链接

【模板】静态区间和(前缀和)

题目描述

给定一个长度为 的数组,有 次询问,每次询问一个区间 的和。

解题思路

本题是静态区间求和问题,即数组本身不会发生改变。对于这类问题,最经典和高效的算法是前缀和

前缀和的核心思想是预处理出一个数组,我们称之为前缀和数组 ,其中 记录了原数组从第 1 个元素到第 个元素的累加和。

为了方便计算,我们通常让前缀和数组的下标从 1 开始,并定义 。 这个前缀和数组可以在 的时间内通过一次遍历计算出来,递推公式为:

当我们需要查询任意区间 (下标从 1 开始)的和时,我们可以利用已经计算好的前缀和数组。区间 的和等于 "前 个元素的和" 减去 "前 个元素的和"。 用公式表示就是:

这样,每次查询只需要进行一次减法操作,时间复杂度为

算法步骤:

  1. 创建一个长度为 的前缀和数组 ,并初始化为 0。
  2. 遍历原数组,计算出所有的
  3. 对于每一次询问 ,直接计算 并输出结果。

代码

#include <iostream>
#include <vector>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    int n, q;
    cin >> n >> q;

    // 前缀和数组,使用 long long 防止求和溢出
    vector<long long> s(n + 1, 0);
    for (int i = 1; i <= n; ++i) {
        int a;
        cin >> a;
        s[i] = s[i - 1] + a;
    }

    // 处理每次查询
    while (q--) {
        int l, r;
        cin >> l >> r;
        cout << s[r] - s[l - 1] << "\n";
    }

    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int q = sc.nextInt();

        // 前缀和数组,使用 long 防止求和溢出
        long[] s = new long[n + 1];
        for (int i = 1; i <= n; ++i) {
            s[i] = s[i - 1] + sc.nextInt();
        }

        // 处理每次查询
        for (int i = 0; i < q; ++i) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            System.out.println(s[r] - s[l - 1]);
        }
    }
}
# 注意:牛客网的 Python I/O 较慢,对于大数据量可能会超时
# 使用下面的快速 I/O 模板可以提高效率
import sys

def main():
    # 读取第一行
    n, q = map(int, sys.stdin.readline().split())
    # 读取第二行数组
    a = list(map(int, sys.stdin.readline().split()))
    
    # 构建前缀和数组
    s = [0] * (n + 1)
    for i in range(n):
        s[i + 1] = s[i] + a[i]
        
    # 读取并处理所有查询
    # sys.stdin.readlines() 会一次性读取所有剩余行
    queries = sys.stdin.readlines()
    for line in queries:
        l, r = map(int, line.split())
        print(s[r] - s[l - 1])

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:前缀和
  • 时间复杂度:。其中 用于构建前缀和数组,之后的 次查询每次只需要 的时间。
  • 空间复杂度:,用于存储前缀和数组。