ARC 081 F - Flip and Rectangles - 单调栈

给你黑白网格,你要翻转一些行和列的颜色,求最大全黑子矩形。
题解:傻逼题。黑白无关紧要。对于一个子矩形来说,若其可行,那么第一行白格子位置对应的列要翻转,翻转后要每一行都全白或者全黑,意味着翻转后每一列都和上一列一样,意味着翻转前每一列都和上一列完全一样或者完全不同即可。然后递推h[i][j]表示(i,j)这个位置和(i,j+1)的位置最下延伸多少,那么每一行朴素暴力就是枚举左右然后乘以区间最小值,然后转为枚举最小值单调栈出左右端点即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define N 2010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int h[N][N],s[N],L[N],R[N],a[N][N];char str[N];
int main()
{
	int n=inn(),m=inn();lint ans=max(n,m);
	rep(i,1,n) { scanf("%s",str+1);rep(j,1,m) a[i][j]=(str[j]=='#'); }
	rep(j,1,m-1) h[n][j]=1;
	for(int i=n-1;i;i--) for(int j=m-1;j;j--)
		if((a[i][j]==a[i][j+1])==(a[i+1][j]==a[i+1][j+1])) h[i][j]=h[i+1][j]+1;
		else h[i][j]=1;
	for(int i=1,t,*v;i<=n;i++)
	{
		t=0,v=h[i];
		for(int j=1;j<=m-1;s[++t]=j++)
			while(t&&v[j]<v[s[t]]) R[s[t--]]=j;
		for(int j=1;j<=t;j++) R[s[j]]=m;
		t=0,v=h[i];
		for(int j=m-1;j>=1;s[++t]=j--)
			while(t&&v[j]<=v[s[t]]) L[s[t--]]=j+1;
		for(int j=1;j<=t;j++) L[s[j]]=1;
		for(int j=1;j<m;j++) ans=max(ans,(R[j]-L[j]+1ll)*v[j]);
	}
	return !printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82789945