Codeforces 1262E Arson In Berland Forest(二维前缀和+二维差分+二分)
题意是需要求最大的扩散时间,最后输出的是一开始的火源点,那么我们比较容易想到的是二分找最大值,但是我们在这满足这样的点的时候可以发现,在当前扩散时间k下,以这个点为中心的(2k+1)2的正方形块内必须全部都是'X'才行,那么要访问这样的块内的'X'个数显然需要使用二维前缀和维护一下就可以O(1)求出个数,那么这部分问题我们解决,接下来就是二分的如何Check,那么既然我们之前找到了这样满足当期扩散时间的点后,我们只需要直接将这块矩形内部的点全部打标记,显然我们可以得知,如果当前扩散时间是满足要求的,那么所有的'X'最后都会被打上标记,那么我们可以利用这一性质,对满足这样的矩形进行二维差分,最后O(n*m)把标记推掉,在check一遍所有被打伤标记的点是不是等于等于一开始'X'的个数,若等于,那么我们可以将区间移至右边,否则移至左边。
最后记得不要用cin,cout,T的死去活来.....
1 // ——By DD_BOND 2 3 #include<bits/stdc++.h> 4 5 using namespace std; 6 7 typedef long long ll; 8 9 const int MAXN=1e6+10; 10 11 inline ll sqr(ll x){ return x*x; } 12 13 char s[MAXN]; 14 15 int main(void) 16 { 17 int n,m; scanf("%d%d",&n,&m); 18 vector<vector<int> >ok (n+2,vector<int>(m+2)); 19 vector<vector<int> >sum(n+2,vector<int>(m+2)); 20 vector<vector<int> >tmp(n+2,vector<int>(m+2)); 21 for(int i=1;i<=n;i++){ 22 scanf("%s",s+1); 23 for(int j=1;j<=m;j++) if(s[j]=='X') sum[i][j]=1; 24 } 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=m;j++) 27 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 28 int l=0,r=(min(n,m)-1)/2,res=0; 29 while(l<=r){ 30 int mid=(l+r)>>1; 31 for(int i=1;i<=n;i++) 32 for(int j=1;j<=m;j++) 33 tmp[i][j]=0; 34 for(int i=mid+1;i<=n-mid;i++) 35 for(int j=mid+1;j<=m-mid;j++) 36 if(sum[i+mid][j+mid]-sum[i-mid-1][j+mid]-sum[i+mid][j-mid-1]+sum[i-mid-1][j-mid-1]==sqr(2*mid+1)){ 37 tmp[i-mid][j-mid]+=1; 38 tmp[i-mid][j+mid+1]+=-1; 39 tmp[i+mid+1][j-mid]+=-1; 40 tmp[i+mid+1][j+mid+1]+=1; 41 } 42 int f=0; 43 for(int i=1;i<=n;i++) 44 for(int j=1;j<=m;j++) 45 if(tmp[i][j]+=tmp[i-1][j]+tmp[i][j-1]-tmp[i-1][j-1]) 46 f++; 47 if(f==sum[n][m]) l=mid+1,res=mid; 48 else r=mid-1; 49 } 50 printf("%d\n",res); 51 for(int i=res+1;i<=n-res;i++) 52 for(int j=res+1;j<=m-res;j++) 53 if(sum[i+res][j+res]-sum[i-res-1][j+res]-sum[i+res][j-res-1]+sum[i-res-1][j-res-1]==sqr(2*res+1)) 54 ok[i][j]=1; 55 for(int i=1;i<=n;i++){ 56 for(int j=1;j<=m;j++) putchar((ok[i][j]?'X':'.')); 57 puts(""); 58 } 59 return 0; 60 }