[ZJOI2007] 棋盘制作

这道题目如果不转化的话,长方形也可以通过单调栈做,正方形要深度思考了DP的方法看能不能做

然而介绍一种trick,当二维平面考虑相邻格子的时候可以考虑这个trick

update 2024.6.25

正方形也可以用经典DP的方法做,见下

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2010;
int n,m;
int tp;
struct
{
	int high,width;
}st[N];
int op[N][N],f[N][N][2],g[N][N];
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-48;s=getchar();}
    return x*f;
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	op[i][j]=read()+1;
	int ans=0;
	memset(g,0x3f,sizeof(g));
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		if(op[i][j]!=op[i][j-1]) f[i][j][0]=f[i][j-1][0]+1;
		else f[i][j][0]=1;
		if(op[i][j]!=op[i-1][j]) f[i][j][1]=f[i-1][j][1]+1;
		else f[i][j][1]=1;//这个f数组是下面用单调栈的时候要用的 
		if(op[i][j]==op[i-1][j-1]&&op[i-1][j]==op[i][j-1]&&op[i][j]!=op[i-1][j])
		g[i][j]=min(g[i-1][j-1],min(g[i-1][j],g[i][j-1]))+1;
		else g[i][j]=1;
		ans=max(ans,g[i][j]);
	}
	printf("%d\n",ans*ans);
	ans=0;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m+1;j++)
	{
		if(op[i][j]==op[i][j-1])
		{
			int width=0;
			while(tp)
			{
				width+=st[tp].width;
				ans=max(ans,st[tp].high*width);
				tp--;
			}
			tp++;
			st[tp].high=f[i][j][1];
			st[tp].width=1;
		}
		else
		{
			if(f[i][j][1]<=f[i][j-1][1])
			{
				int width=0;
			    while(tp&&st[tp].high>=f[i][j][1])
			    {
				    width+=st[tp].width;
				    ans=max(ans,st[tp].high*width);
				    tp--;
			    }
			    tp++;
			    st[tp].high=f[i][j][1];
			    st[tp].width=width+1;
			}
			else
			{
				tp++;
				st[tp].high=f[i][j][1];
				st[tp].width=1;
			}
		}
	}
	printf("%d",ans);
	return 0;
}
posted @ 2024-05-07 21:36  最爱丁珰  阅读(1)  评论(0编辑  收藏  举报