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);
}
还有一种方法是悬线法但是被我咕咕咕了