这篇主要是来介绍前缀和的QAQ。
前缀和有一维的和二维的,一维的很容易理解,高中数学必修5第二章数列给出了前n项和的概念,就是前缀和。一维的我们在这里简单说一句。
一维前缀和
预处理:在输入一个数列的时候累加
查询区间和:查询[i,j]区间全部元素的和--sum[j]-sum[i-1]
二维前缀和
预处理:用到了容斥原理的知识。即求矩阵左上角的顶点与当前点所围成的矩形所覆盖的权值。
设f[][]为前缀和数组,则f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j]
(注:图片来源@ShawnZhou 神犇,原文地址,感谢,侵删。)
查询区间和:
对于一个边长为R的正方形,以(i,j)作为右下角的,那它矩阵中的和为
s[i][j]-s[i-R,j]-s[i,j-R]+s[i-R,j-R]
放两道例题跑(
例题1 [HNOI2003]激光炸弹
前缀和+枚举边长
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int n,R,ans; 5 int f[5090][5090]; 6 int main() 7 { 8 scanf("%d%d",&n,&R); 9 for(int i=1;i<=n;i++) 10 { 11 int x=0,y=0,z=0; 12 scanf("%d%d%d",&x,&y,&z); 13 f[x+1][y+1]=z; 14 } 15 for(int i=1;i<=5001;i++) 16 for(int j=1;j<=5001;j++) 17 { 18 f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1]; 19 } 20 for(int i=0;i<=5000-R;i++) 21 for(int j=0;j<=5000-R;j++) 22 { 23 int tmp=f[i+R][j+R]-f[i+R][j]-f[i][j+R]+f[i][j]; 24 ans=max(tmp,ans); 25 } 26 printf("%d",ans); 27 return 0; 28 }
例题2 最大正方形
可能是隐藏在dp标签下的一个叛徒这题我觉得用前缀和最简单,而且还是01矩阵,只要预处理出前缀和然后枚举最大正方形的边长大小,再看矩阵中权值和是否等于边长*边长即可。以及注意边界问题。
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 int n,m,ans; 7 int f[200][200]; 8 9 int main() 10 { 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;i++) 13 for(int j=1;j<=m;j++) 14 { 15 scanf("%d",&f[i][j]); 16 f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1]; 17 } 18 for(int i=1;i<=n;i++) 19 for(int j=1;j<=m;j++) 20 for(int k=1;k<=max(n,m);k++) 21 { 22 if(i-k<1) continue; 23 if(j-k<1) continue; 24 int qwq=f[i][j]-f[i-k][j]-f[i][j-k]+f[i-k][j-k]; 25 if(qwq==k*k) ans=max(ans,k); 26 } 27 printf("%d",ans); 28 return 0; 29 }
*update on 10-18
noip2014无线网络发射器选址
二维前缀和裸题,当然也可直接枚举中心统计。
但是发现自己前缀和这理解可能有点问题hhh。
其实是这样的qwq。(当然变量名不能用x1y1之类的啦)
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 5 using namespace std; 6 typedef long long ll; 7 8 int d,n; 9 ll tot,ans; 10 ll w[500][500]; 11 12 int main() 13 { 14 // freopen("1.out","w",stdout); 15 scanf("%d%d",&d,&n); 16 for(int i=1;i<=n;i++) 17 { 18 int x=0,y=0,z=0; 19 scanf("%d%d%d",&x,&y,&z); 20 w[x][y]=z; 21 } 22 for(int i=0;i<=128;i++) 23 for(int j=0;j<=128;j++) 24 w[i][j]+=w[i-1][j]+w[i][j-1]-w[i-1][j-1]; 25 for(int i=0;i<=128;i++) 26 for(int j=0;j<=128;j++) 27 { 28 //if(i-d<0||i+d>128||j-d<0||j+d>128) continue; 29 int tx=(i+d<=128) ? (i+d) : 128; 30 int ty=(j+d<=128) ? (j+d) : 128; 31 int lx=(i-d>=0) ? (i-d) : 0; 32 int ly=(j-d>=0) ? (j-d) : 0; 33 ll tmp=w[tx][ty]-w[tx][ly-1]-w[lx-1][ty]+w[lx-1][ly-1]; 34 //if(i==120&&j==120) cout<<tx<<" "<<ty<<" "<<lx<<" "<<ly; 35 //if(i==120&&j==120) cout<<tmp; 36 if(tmp>ans) ans=tmp,tot=1; 37 else if(tmp==ans) tot++; 38 } 39 printf("%lld %lld",tot,ans); 40 return 0; 41 }