目录
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,多减了一个)
之后将差分数组求前缀和就行