BZOJ118——激光炸弹(二维前缀和)

二维前缀和

题意:给你一个5000*5000的格子,有些格子里面有值,询问一个rrr*r的正方形的最大值

由于数据范围是5000,刚好不需要离散化,直接预处理出二维前缀和,利用差分O(1)查询每个正方形,复杂度O(n2)O(n^2)

二维前缀和写法有很多,主要是两种

for(i=1;i<=5001;i++)
    		for(j=1;j<=5001;j++) a[i][j]+=a[i-1][j];
for(i=1;i<=5001;i++)
    		for(j=1;j<=5001;j++) a[i][j]+=a[i][j-1];

	for(int i=1;i<=5001;i++){
	    	for(int j=1;j<=5001;j++){
	        		a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
    		}
	}

然后每次询问的时候利用容斥原理做一下

比如一个以(i,j)(i,j)为右上角,(ir,jr)(i-r,j-r)为左下角的矩阵的值为t[i][j]t[i][jr]t[ir][j]+t[ir][jr]t[i][j]-t[i][j-r]-t[i-r][j]+t[i-r][j-r]

可以自己画图手推一下

代码

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
const int N=5005;
int t[N][N],m,n,r;
int main(){
    n=read(),r=read();
    for(int i=1;i<=n;i++){
        int x=read(),y=read(),a=read();
        t[x+1][y+1]+=a;
    }
    for(int i=1;i<=5001;i++){
        for(int j=1;j<=5001;j++){
            a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        }
    }
    int ans=0;
    for(int i=r;i<=5001;i++){
        for(int j=r;j<=5001;j++){
            ans=max(ans,t[i][j]-t[i][j-r]-t[i-r][j]+t[i-r][j-r]);
        }
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366410.html