首页 > 编程语言 > 详细

算法:前缀和与差分

时间:2020-09-20 08:45:21      阅读:48      评论:0      收藏:0      [点我收藏+]

算法:前缀和与差分

一维前缀和

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;
}

算法:前缀和与差分

原文:https://www.cnblogs.com/trafalgar999/p/13698673.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!