CF1227E Arson In Berland Forest 二分+二维前缀和+差分

题意:

在一个无限大的矩阵中,每个位置是一棵树。在一个$ n \times m$ 的子矩阵中,发生了一场火灾,一些树被摧毁了。被摧毁的树用字符 X 表示,未被摧毁的树用字符 . 表示。子矩阵外的树都没有被摧毁。

  • 在 0 时刻,有些树是自发着火的。
  • 接下来的每一分钟内,每一棵着火(也即被摧毁)的树,会使得它周围的 8 个相邻的树着火。
  • 在第 T 分钟初,火灾停止。

现在给定最后被摧毁的树,求最大可能的 T,并求出任意一种满足的、自发着火的树的集合。

范围&性质 \(1\leq n,m\leq 10^6,1\leq n\times m\leq 10^6\)

分析:

分析可以发现对于小于答案的T,一定满足题意,所以T的大小具有单调性,我们只需要二分出一个T,然后枚举每一个点判断它是否可以作为起始的自燃点,此时的时间复杂度为\(\omicron(nmt^2log)\),为了降低时间复杂度我们采取二维前缀和的方法使检验每一个点能否作为自燃点的复杂度降到\(\omicron(1)\)的,同时对于每一个自燃点覆盖的矩形区域进行差分处理,最后对差分数组进行求和,统计权值为正的点的个数,若等于原有X的个数,则将mid增大反之减小,总的复杂度为\(\omicron(nmlog)\)

代码:

吐槽一句这个题真的是赢在码量上,单论思维难度,没有2300的难度

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
	const int maxn = 1e6+5;
	int n,m;
	vector<int> sum[maxn],tot[maxn];
	vector<bool> ans[maxn];
	char ch[maxn];
	
	bool check(int x)
	{
		for(int i=0;i<=n;i++)
		{
			for(int j=0;j<=m;j++)
			{
				tot[i][j]=0;
			}
		}
		for(int i=x+1;i<=n-x;i++)
		{
			for(int j=x+1;j<=m-x;j++)
			{
				if(sum[i+x][j+x]-sum[i-x-1][j+x]-sum[i+x][j-x-1]+sum[i-x-1][j-x-1]==(2*x+1)*(2*x+1))
				{
					tot[i+x+1][j+x+1]+=1;
					tot[i-x][j+x+1]+=-1;
					tot[i+x+1][j-x]+=-1;
					tot[i-x][j-x]+=1;
				}
			}
		}
		
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				printf("%d",tot[i][j]);
			}
			puts(" ");
		}
		puts(" ");
		
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				if(tot[i][j]+=tot[i-1][j]+tot[i][j-1]-tot[i-1][j-1])
				{
					cnt++;
				}
			}
		}
        for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				printf("%d",tot[i][j]);
			}
			puts(" ");
		}
		puts(" ");
		return cnt==sum[n][m];
	}
	
	void work()
	{
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n+1;i++)
		{
			for(int j=0;j<=m+1;j++)
			{
				sum[i].push_back(0);
				tot[i].push_back(0);
				ans[i].push_back(false);
			}
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%s",ch+1);
			for(int j=1;j<=m;j++)
			{
				sum[i][j]=(ch[j]=='X'?1:0);
				sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
			}
		}
		int mid,l=0,r=(min(n,m)-1)/2,res;
		while(l<=r)
		{
			mid=(l+r)>>1;
			if(check(mid))
			{
				res=mid;
				l=mid+1;
			}
			else r=mid-1;
		}
		printf("%d\n",res);
		for(int i=res+1;i<=n-res;i++)
		{
			for(int j=res+1;j<=m-res;j++)
			{
				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]==(2*res+1)*(2*res+1))
				{
					ans[i][j]=true;
				}
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				putchar((ans[i][j]?'X':'.'));
			}
			puts(" ");
		}
	}
	
}

int main()
{
	zzc::work();
	return 0;
}
原文地址:https://www.cnblogs.com/youth518/p/13649615.html