P1169棋盘制作

传送
刚想提交评测姬就炸了所以我也不知道A没A
评测姬好了我也A了
暴力想法:对每个点\(bfs\),算出以这个点为左上角的最大合法矩形。复杂度\(O(n^3)\),但是因为数据过水可以A掉

单调栈法

考虑优化暴力:我们可以算出每个点在一行内最多向右扩展多长。这样计算点\((i,j)\)为左上角的最大矩形时,从上往下扫。把每个点最多向右扩展的距离用矩形块表示,求面积时的情况:

这样就可以用单调栈求最大矩形面积。所以最大的矩形面积就可以搞定。
最大正方形面积:在用单调栈的时候会处理出每个矩形块能扩展出的最大矩形。用每个最大矩形中能切出的最大正方形来更新答案。
\(Code\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<cstring>
#include<cstdlib>
#include<set>
#define pa pair<int,int>
#define pi pair<ull,ll>
using namespace std;
const int inf=2147483640;
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
	char ch=getchar();
	ll x=0;bool f=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
const int N=2009;
int n,m,ans1,ans2;
int lm[N][N],pu[N],pd[N],top;//lm[i][j]表示点(i,j)最远向右扩展多少
bool a[N][N];
struct ST{
	int h,pos;
}sta[N];
ST make(int h,int pos){
	ST a;
	a.h=h;a.pos=pos;
	return a;
}
void orz(int x,int y){
	top=0;int lst=n;
	sta[++top]=make(lm[x][y],x);
	for(int i=x;i<=n;i++){
		if(i!=x&&a[i][y]==a[i-1][y]) {lst=i-1;break;}
		pu[i]=i;//pu表示第i行最往上能扩展到第几行
		if(lm[i][y]>sta[top].h){sta[++top]=make(lm[i][y],i);}
		else { while(top&&sta[top].h>=lm[i][y]) {top--;}
			pu[i]=sta[top].pos+1;
			pu[i]=max(pu[i],x);//处理边界
			sta[++top]=make(lm[i][y],i);
		}
	}
	top=0;sta[++top]=make(lm[lst][y],lst);
	for(int i=lst;i>=x;i--){
		pd[i]=i;//pd表示向下最多扩展到第几行
		if(lm[i][y]>sta[top].h){sta[++top]=make(lm[i][y],i);}
		else { while(top&&sta[top].h>=lm[i][y]) {top--;}
			pd[i]=sta[top].pos-1;
			if(pd[i]==-1) pd[i]=lst;
			sta[++top]=make(lm[i][y],i);
		}
	}
	int S=0;
	for(int i=x;i<=lst;i++){
        int s=(pd[i]-pu[i]+1)*lm[i][y];
        int aa=pd[i]-pu[i]+1,bb=lm[i][y];
		ans2=max(ans2,s);
		int l1=min(aa,bb);
		ans1=max(ans1,l1*l1);
	}
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)
	   for(int j=1;j<=m;j++) a[i][j]=read();
	for(int i=1;i<=n;i++){//处理最远向右扩展
		lm[i][m]=1;
		for(int j=m-1;j>=1;j--){
			if(a[i][j]!=a[i][j+1]) lm[i][j]=lm[i][j+1]+1;
			else lm[i][j]=1;
		}
	}   
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){;
			orz(i,j);
		}
	}
	printf("%d\n%d\n",ans1,ans2);   
}

还有一种方法是悬线法但是被我咕咕咕了

posted @ 2020-10-30 16:52  千载煜  阅读(60)  评论(0编辑  收藏  举报