前缀和与差分

目录

前缀和

一维前缀和

构造数组

查询

二维前缀和

构造数组

查询

差分

一维差分

构造数组

应用 

二维差分

构造数组

应用

csp第二题常年考察内容......

前缀和

所谓前缀和可以理解为数学里的数列前n项和,是用来求子区间和的一种便捷方法,与暴力解法相比,其时间复杂度低,大大提高了运行效率。

一维前缀和

构造数组

对于所给的一维数组a[n],我们先要构造其前缀和数组s[n]。按照前缀和的定义我们很容易就能想到:s[n-1]=a[0]+a[1]......a[n-1],s[n]=s[n-1]+a[n]。

#include <iostream>
#define n 100
using namespace std;
int main()
{
    int a[n],s[n]
    s[0]=a[0];
    for(int i=1;i<n;i++)
    {
        s[n]=s[n-1]+a[n];
    }
    return 0;
}

查询

我们不难想到i到j这段子区间和就是:s[j]-s[i]

二维前缀和

构造数组

和一维前缀和一样,我们需要构造一个前缀和数组s[i][j]。利用前缀和的思想:我们需要通过前面已知的前缀和来推出后面未知的前缀和。

如图,一个二维矩阵(黑色部分)面积=蓝色部分面积+紫色部分面积+右下角小方块面积-红色部分面积(多加了一次)

由此可以得出:s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1]

#include <iostream>
#define n 100
using namespace std;
int main()
{
    int a[n][n],s[n][n]
    s[0][0]=a[0][0];
    s[0][1]=s[0][0]+a[0][1];
    s[1][0]=s[0][0]+a[1][0];
    for(int i=1;i<n;i++)
        for(int j=1;j<n;j++)
        {
            s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
        }
    return 0;
}

查询

我们想得到的是以(x1,y1)为左上角,以(x2,y2)为右下角的子矩阵的面积(即下图中红色矩形的面积),我们知道的有绿色矩形、蓝色矩形、橙色矩形、紫色矩形的面积。

 不难得出红色矩形面积=s[x2][y2](蓝色矩形面积)-s[x2][y1-1](橙色矩形面积)-s[x1-1][y2](紫色矩形面积)+s[x1-1][y1-1](绿色矩形面积)(多减了一次)

差分

所谓差分可以理解为前缀和的逆运算,就是将数列中每一项分别与前一项做差。

一维差分

构造数组

对于所给的一维数组a[n],我们先要构造其一维差分数组d[n]。按照差分的定义我们很容易就能想到:d[n]=a[n]-a[n-1]

#include <iostream>
#define n 100
using namespace std;
int main()
{
    int a[n],d[n]
    a[0]=0;
    for(int i=1;i<n;i++)
        d[n]=a[n]-a[n-1];
    return 0;
}

应用 

将原序列[i,j]中全部的元素+k/-k

这个可以转换为:

1.d[i]+/-=k,d[j+1]-/+=k

2.将差分数组求前缀和

二维差分

构造数组

和一维差分一样,我们需要构造一个二维差分数组s[i][j]。利用差分的思想:用当前位置原矩形的面积减去前面相邻的原矩形的面积

如图:差分面积d[i][j]=a[i][j](蓝色矩形面积)-a[i-1][j](紫色矩形面积)-a[i][j-1](橙色矩形面积)+a[i-1][j-1](红色矩形面积,多减了一次)

注意d[i][j]!=a[i][j]-a[i-1][j-1](边界) 

应用

将原序列(x1,y1)到(x2,y2)中全部的元素+k/-k

这个可以转换为:

d[x1][y1]+=k(蓝色矩形面积加k)

d[x1][y2+1]-=k(紫色矩形面积减k,多加了一个)

d[x2+1][y1]-=k(橙色矩形面积减k,多加了一个)

d[x2+1][y2+1]+=k(红色矩形面积加k,多减了一个)

 之后将差分数组求前缀和就行

  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LIKE呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值