6488. 【GDOI2020模拟02.29】土地勘测land

题目描述


题解

每次可以找一维折半,所以答案不超2log

反着做,变成每次把两个相邻的区间合并

枚举答案,维护f[i][j][k]表示当前第i行j~k列最多能向下到哪一行,g[i][j][k]表示列

每次先自己转移自己,然后考虑用另一个数组转移

比如对于当前的f[i][j][k],可以转到满足g[j][i][l]>=k的l(g已经转移过自己),画图理解

g同理

而当一个矩形包含另一个矩形时,被包含的矩形的操作次数必然不增,同理在某一条边界上缩一格时也不增

因此可以单调维护l

其中自己转移自己之后可以直接用回老数组,具体感性理解

关于转移顺序与时间: https://www.cnblogs.com/gmh77/p/12392514.html

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define file
using namespace std;

bool a[221][221];
int sum[221][221],f[222][221][221],g[222][221][221],n,m,i,j,k,l,ans;
char ch;

bool pd(int x1,int y1,int x2,int y2)
{
	int s=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
	return !s || s==(x2-x1+1)*(y2-y1+1);
}

void init()
{
	fo(j,1,m)
	{
		fo(k,j,m)
		{
			fo(i,1,n)
			{
				f[i][j][k]=max(f[i-1][j][k],i-1);
				while (f[i][j][k]<n && pd(i,j,f[i][j][k]+1,k))
				++f[i][j][k];
			}
		}
	}
	fo(j,1,n)
	{
		fo(k,j,n)
		{
			fo(i,1,m)
			{
				g[i][j][k]=max(g[i-1][j][k],i-1);
				while (g[i][j][k]<m && pd(j,i,k,g[i][j][k]+1))
				++g[i][j][k];
			}
		}
	}
}

int main()
{
	freopen("land.in","r",stdin);
	#ifdef file
	freopen("land.out","w",stdout);
	#endif
	
	scanf("%d%d",&n,&m);
	fo(i,1,n)
	{
		fo(j,1,m)
		{
			ch=getchar();
			while (ch!='.' && ch!='#')
			ch=getchar();
			
			a[i][j]=ch=='#';
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
		}
	}
	
	fo(i,1,m){fo(j,i,m)f[n+1][i][j]=n;}
	fo(i,1,n){fo(j,i,n)g[m+1][i][j]=m;}
	
	init();
	
	while (!(f[1][1][m]==n || g[1][1][n]==m))
	{
		++ans;
		
		fo(j,1,m)
		{
			fo(k,j,m)
			{
				l=0;
				fo(i,1,n)
				{
					l=max(l,i-1);
					while (l<n && g[g[j][i][l+1]+1][i][l+1]>=k)
					++l;
					
					f[i][j][k]=max(f[f[i][j][k]+1][j][k],l);
				}
			}
		}
		fo(j,1,n)
		{
			fo(k,j,n)
			{
				l=0;
				fo(i,1,m)
				{
					l=max(l,i-1);
					while (l<m && f[j][i][l+1]>=k)
					++l;
					
					g[i][j][k]=max(g[g[i][j][k]+1][j][k],l);
				}
			}
		}
	}
	printf("%d\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}
posted @ 2020-03-01 22:56  gmh77  阅读(211)  评论(0编辑  收藏  举报