1.前缀和的应用
(1)一维:已知一个一维数组,给定区间( l , r ),求区间和。
(2)二维:已知一个二维数组,给定起点终点坐标( x1 , y1 ),( x2 , y2 ),求以起点为左上角,终点为右下角构成的矩阵的和。
2.一维前缀和
核心思想:
(1)对每一个 i ,求出前 i 个数的和,存在 tot [ i ] 里。
(2)[ 3 , 5 ] 区间和 = [ 1 , 5 ] 区间和 - [ 1 , 2 ] 区间和 #注意这里不是 - [ 1 , 3 ] , 3 不能包含在里面
#include<iostream>
using namespace std;
int n,m,a[100010],tot[100010];
int f(int l,int r)
{
if (l==1)
return tot[r];
return tot[r]-tot[l-1]; !!! 注意 tot [l-1] , 不是 tot [l]
}
int main()
{
int i;
int l,r;
cin>>n;
for (i=1;i<=n;i++)
{
cin>>a[i];
tot[i]=tot[i-1]+a[i];
}
cin>>m;
while (m--)
{
cin>>l>>r;
cout<<f(l,r)<<endl;
}
return 0;
}
3.二维前缀和
核心思想:
(1)预处理:算出每个点,以该点为右下角,( 1 , 1 )为左上角的矩阵和
s ( x , y ) = a [ x ] [ y ] + s ( x , y-1 ) + s ( x-1, y ) - s ( x , y ) //减去多加上一次的重合部分
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]+a[i][j]-s[i-1][j-1];
(2)计算给定矩阵和
tot { ( x1 , y1 ) , ( x2 , y2 ) } = s ( x2 , y2 ) - s ( x2 , y1-1 ) - s ( x1-1, y2 ) + s ( x1 , y1 ) //加上多减去一次的重合部分
cin>>x1>>y1>>x2>>y2;
tot=s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
4.例题——洛谷P1719
#include<iostream>
using namespace std;
int n,ans,a[130][130],s[130][130];
int main()
{
int i,j;
int x1,y1,x2,y2;
cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
cin>>a[i][j];
s[i][j]=a[i][j]+s[i][j-1]+s[i-1][j]-s[i-1][j-1];
}
for (x1=1;x1<=n;x1++)
for (y1=1;y1<=n;y1++)
for (x2=x1;x2<=n;x2++)
for (y2=y1;y2<=n;y2++)
ans=max(ans,s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
cout<<ans;
return 0;
}