蓝桥杯C++基础算法-前缀和

这段代码实现了一个基于前缀和的区间和查询功能。它的核心思想是通过预先计算一个前缀和数组 s,使得每次查询某个区间的和时,可以在常数时间内完成。以下是代码的详细思路解析:


1. 问题背景

假设有一个数组 a,长度为 n,我们需要多次查询某个区间 [l, r] 内所有元素的和。直接计算区间和的方法是遍历区间 [l, r] 并累加,但这会导致每次查询的时间复杂度为 O(n),效率较低。为了优化查询效率,可以使用前缀和技术。


2. 前缀和的概念

前缀和数组 s 是一个辅助数组,其中 s[i] 表示数组 a 从第 1 个元素到第 i 个元素的累加和,即:

cpp复制

s[i] = a[1] + a[2] + ... + a[i]

通过前缀和数组,可以快速计算任意区间 [l, r] 的和:

cpp复制

sum[l, r] = s[r] - s[l - 1]

这里的关键是利用了前缀和的性质:s[r] 是从 a[1]a[r] 的累加和,s[l - 1] 是从 a[1]a[l - 1] 的累加和,因此它们的差值就是区间 [l, r] 的和。


3. 代码逻辑解析

(1) 输入部分

cpp复制

cin >> n >> m;  // 输入数组长度 n 和查询次数 m
for (int i = 1; i <= n; i++) cin >> a[i];  // 输入数组 a
  • 用户输入数组的长度 n 和查询次数 m

  • 接着输入数组 a 的每个元素。数组 a 的索引从 1 开始,方便后续计算。

(2) 前缀和数组的计算

cpp复制

s[0] = 0;  // 初始化 s[0] 为 0
for (int i = 1; i <= n; i++) 
    s[i] = s[i - 1] + a[i];  // s[i] 是从 a[1] 到 a[i] 的累加和
  • 初始化 s[0] = 0,表示从第 1 个元素之前的累加和为 0。

  • 使用循环计算前缀和数组 s

    • s[i] 的值等于 s[i - 1](前一个前缀和)加上当前元素 a[i]

    • 这样,s[i] 就存储了从 a[1]a[i] 的累加和。

(3) 查询部分

cpp复制

while (m--)
{
    int l, r;
    cin >> l >> r;  // 输入查询区间 [l, r]
    cout << s[r] - s[l - 1] << endl;  // 输出区间和
}
  • 用户输入查询区间 [l, r]

  • 利用前缀和数组快速计算区间和:

    • 区间 [l, r] 的和等于 s[r] - s[l - 1]

    • 这里利用了前缀和的性质,计算结果的时间复杂度为 O(1)

  • 输出查询结果。


4. 代码效率分析

  • 时间复杂度

    • 计算前缀和数组的时间复杂度为 O(n)

    • 每次查询的时间复杂度为 O(1)

    • 总时间复杂度为 O(n + m),其中 n 是数组长度,m 是查询次数。

  • 空间复杂度

    • 使用了一个额外的前缀和数组 s,空间复杂度为 O(n)


5. 示例运行

输入:

plaintext复制

5 3
1 2 3 4 5
1 3
2 4
1 5
运行过程:
  1. 输入数组长度 n = 5 和查询次数 m = 3

  2. 输入数组 a = [1, 2, 3, 4, 5]

  3. 计算前缀和数组 s

    • s[0] = 0

    • s[1] = 1

    • s[2] = 3

    • s[3] = 6

    • s[4] = 10

    • s[5] = 15

  4. 处理查询:

    • 查询 [1, 3] 的和:s[3] - s[0] = 6

    • 查询 [2, 4] 的和:s[4] - s[1] = 9

    • 查询 [1, 5] 的和:s[5] - s[0] = 15

输出:

plaintext复制

6
9
15

6. 总结

这段代码的核心思路是通过前缀和技术,将区间和查询的时间复杂度从 O(n) 优化到 O(1)。通过预先计算一个前缀和数组 s,可以快速完成多次区间和查询,适用于需要频繁查询区间和的场景。

完整代码

#include 
using namespace std;
const int N = 1e5 + 10;

int n, m;
int a[N], s[N];  // a 存储原始数组,s 存储前缀和

int main()
{
    cin >> n >> m;  // 输入数组长度 n 和查询次数 m
    for (int i = 1; i <= n; i++) cin >> a[i];  // 输入数组 a

    // 计算前缀和数组 s
    s[0] = 0;  // 初始化 s[0] 为 0
    for (int i = 1; i <= n; i++) 
        s[i] = s[i - 1] + a[i];  // s[i] 是从 a[1] 到 a[i] 的累加和

    // 处理 m 次查询
    while (m--)
    {
        int l, r;
        cin >> l >> r;  // 输入查询区间 [l, r]
        cout << s[r] - s[l - 1] << endl;  // 输出区间和
    }

    return 0;
}

你可能感兴趣的:(C++,算法,蓝桥杯,c++)