题目

Description
【JZOJ 省选模拟】土地勘测land_经验分享

Input
【JZOJ 省选模拟】土地勘测land_题解_02

Output
一行一个整数,输出土地的不平整程度。

Sample Input
样例 1 输入:
3 3

.##
.##

样例 2输入:
6 7
.####.#
#…#.
#…#.
#…#.
.####.#
#…##

Sample Output
样例 1 输出:
2
样例 2输出:
4

Data Constraint
【JZOJ 省选模拟】土地勘测land_题解_03

思路

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

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

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

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

g同理

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

因此可以单调维护l

代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Max(a,b) if (a<b)a=b
#define N 225
using namespace std;

int n,m,a[N][N],b[N][N],f[2][N][N][N];
char s[N];
int main()
{
	freopen("land.in","r",stdin);
	freopen("land.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for (int j=1;j<=m;j++)
		b[i][j]=b[i-1][j]+(a[i][j]=(s[j]=='.'));
	}
//init
	for (int i=1;i<=n;i++)a[i][m+1]=a[i][m];
	for (int j=1;j<=n;j++)
	for (int k=j;k<=n;k++)
	f[0][m+1][j][k]=f[1][m+1][j][k]=m+1;
	for (int i=m;i;i--)
	for (int j=1;j<=n;j++)
	for (int k=j;k<=n;k++)
	{
		if (b[k][i]-b[j-1][i]&&b[k][i]-b[j-1][i]!=k-j+1)
		f[0][i][j][k]=i;
		else
		if (a[k][i]!=a[k][i+1])f[0][i][j][k]=i+1;
		else f[0][i][j][k]=f[0][i+1][j][k];
	}
//init end(ok)
	for (int yjy=0,o=0;;yjy++,o=!o)
	{
		if (f[o][1][1][n]>m)
		{printf("%d\n",yjy);return 0;}
		for (int i=1;i<=m;i++)
		for (int j=1;j<=n;j++)
		for (int k=j,g=j,G=0;k<=n;k++)
		{
			f[!o][i][j][k]=f[o][f[o][i][j][k]][j][k];
			if (g>j)G=min(f[o][i][j][g-1],f[o][i][g][k]);
			while (g<k&&G<=min(f[o][i][j][g],f[o][i][g+1][k]))
			G=min(f[o][i][j][g],f[o][i][g+1][k]),g++;
			Max(f[!o][i][j][k],G);
		}
	}
}