算法:前缀和与差分

算法:前缀和与差分

一维前缀和

a[N]为一数组,若存在s[N], 使得s[i]=a[1]+a[2]+a[3]+...+a[i], 则称s[N]为a[N]的前缀和数组。

前缀和用来求一个数组内给定区间所有元素的和,将其时间复杂度降为O(1).

#include <iostream>

using namespace std;

const int N = 100010;

int n, m;
int a[N], s[N];
int main()
{
    //ios::sync_with_stdio(false); //提高cin读取速度,使scanf失效

    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++)
        s[i] = s[i - 1] + a[i]; //前缀和初始化

    while (m--)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]); //区间和的计算
    }

    return 0;
}

二维前缀和

二维前缀和与一维的类似,即s[i][j]是(i,j)位置的左上部分的和。

// 子矩阵的和
#include <iostream>
using namespace std;

const int N = 1010;
int n, m, q;
int a[N][N], 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", &a[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--)
    {
        int 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;
}

差分

差分可以看作是前缀和的逆运算。对于一个数组a[N],如果存在b[N],使得a[N]是b[N]的前缀和,那么则称b[N]是a[N]的差分。

差分可以很快速地将一个数组中的一段区间内的数加上一个数值,只需要在其差分数组的这个区间内的第一个数加上这个数,最后一个数减去这个数即可。

#include <iostream>

using namespace std;

const int N = 100010;

int n, m;
int a[N], b[N];

void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n; i++)
    {
        insert(i, i, a[i]);	//将a[n]看作是全为0的数组每次在一个位置上插入a[i]
    }
    while (m--)
    {
        int l, r, c;
        scanf("%d%d%d", &l, &r, &c);
        insert(l, r, c);
    }
    for (int i = 1; i <= n; i++)
    {
        b[i] += b[i - 1];
    }
    for (int i = 1; i <= n; i++)
        printf("%d", b[i]);
    return 0;
}

二维差分

#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
int a[N][N], b[N][N];

void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}

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", &a[i][j]);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            insert(i, j, i, j, a[i][j]);
    while (q--)
    {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);
    }

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            printf("%d", b[i][j]);
            puts("");
        }
    return 0;
}
posted @ 2020-09-20 07:43  trafalgar999  阅读(171)  评论(0编辑  收藏  举报