一维二维前缀和

74 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第24天,点击查看活动详情

前缀和

一维前缀和

前缀和的作用:

为了更快,可以多次查找一个区间的累加和,例如:要求[left,right]区间的和,如果没有前缀和,就需要遍历数组求和,时间复杂度O(N), 如果有前缀和:时间复杂度是O(1)

S[i] = a[0] + a[1] + ... + a[i]

image-20221029164328599

如何构造一维前缀和数组呢

前缀和数组的表达式:presum[i] = presum[i-1] + arr[i] ,其中preSum[0] = a[0]


例子:

image-20221030113512923

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n,m;
    cin >> n >> m;
    vector<int> a(n+1,0);
    vector<int> s(n+1,0);
    for(int i = 1 ; i <= n ;++i) cin >> a[i];
    //构造前缀和数组
    s[0] = a[0];
    for(int i = 1 ; i <= n ;++i) s[i] = s[i-1]+a[i];
    
    while(m--) //m次询问
    {
        int l,r;
        cin >> l >> r; //求[left,right]区间元素的和
        if(l == 0)
            cout << s[r] << endl;
        else
            cout << s[r] - s[l-1] << endl;
    }
    return 0;
}

二维前缀和

假设:S[i, j] 表示的是第i行j列格子左上部分所有元素的和, 如果想求以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为 S

image-20221029170102927

S = S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]


如何求构造二维前缀和数组呢

s[i][j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j] //s[i][j]i行j列及其左上方所有元素的累加和

image-20221029170943263

image-20221031102505787


例子

image-20221030113704325

#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int s[N][N];
​
int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i ++ )  //输入数据
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &s[i][j]);
    
    //构造二维前缀和数组
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
​
    while (q -- ) //进行q次询问
    {
        int x1, y1, x2, y2; //求(x1,y1)到(x2,y2)围成的矩阵的和
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
    }
    return 0;
}