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);
}