把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P1169 [ZJOI2007]棋盘制作

题面传送门
闲着没事开始清任务计划。
显然单调栈处理出一条列当前的最高的点,然后单调栈向左右拓展找到第一个小于的点,细节处理一下即可。
时间复杂度\(O(n^2)\)
代码实现:

#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,f[2039],a[2039][2039],ans,tot,pus,head,l[2039],r[2039],st[2039],sh;
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	register int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++) scanf("%d",&a[i][j]);
	}
	for(i=1;i<=m;i++) f[i]=1;
	for(i=1;i<=n;i++){
		if(i^1){
			for(j=1;j<=m;j++) f[j]=(a[i][j]==a[i-1][j]?1:f[j]+1);
		}
		sh=pus=0;
		for(j=1;j<=m;j++) l[j]=0,r[j]=m+1;
		for(j=1;j<=m;j++){
			if(j^1) pus=(a[i][j]==a[i][j-1]?j-1:pus);
			while(sh&&f[st[sh]]>=f[j]) sh--;
			if(sh)l[j]=st[sh];l[j]=max(l[j],pus);st[++sh]=j;
		}
		sh=0;pus=m+1;
		for(j=m;j;j--){
			if(j^1) pus=(a[i][j]==a[i][j+1]?j+1:pus);
			while(sh&&f[st[sh]]>=f[j]) sh--;
			if(sh) r[j]=st[sh];r[j]=min(r[j],pus);st[++sh]=j;
		}
		for(j=1;j<=m;j++) tot=max(tot,(r[j]-l[j]-1)*f[j]),ans=max(ans,min(r[j]-l[j]-1,f[j])*min(r[j]-l[j]-1,f[j]));
	}	
	printf("%d\n%d\n",ans,tot);
} 
posted @ 2021-02-01 13:45  275307894a  阅读(52)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end