前缀和小结 By cellur925

这篇主要是来介绍前缀和的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 } 
View Code

例题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 }
View Code

 


 

*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 }
View Code

 

posted @ 2018-08-24 17:06  cellur925&Chemist  阅读(343)  评论(0编辑  收藏  举报