唉……这种题放在NOIP以前我是会做的……但是为什么现在反而不会了……
单调栈。预处理每个点向上能扩展的最大距离,左右用两遍单调栈扫一遍。注意边界。
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<cctype> using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int q[2010][2010]; int d[2010][2010][2]; int w[2020];int s[2020]; int stack[2020],top; int ans; int cnt; int main(){ int n=read(),m=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ q[i][j]=read()^((i+j+1)%2); int now=q[i][j]; d[i][j][now]=q[i-1][j]==now?d[i-1][j][now]+1:1; } for(int i=1;i<=n;++i){ memset(w,0,sizeof(w)); top=0; for(int j=1;j<=m;++j){ w[j]=j; while(top&&d[i][stack[top]][0]>d[i][j][0]) w[stack[top--]]=j-1; stack[++top]=j; } //while(top) w[stack[top--]]=n; memset(s,0,sizeof(s)); top=0; for(int j=m;j>=1;--j){ s[j]=j; while(top&&d[i][stack[top]][0]>d[i][j][0]) s[stack[top--]]=j+1; stack[++top]=j; } //while(top) s[stack[top--]]=1; for(int j=1;j<=m;++j){ ans=max(ans,(w[j]-s[j]+1)*d[i][j][0]); int MIN=min(w[j]-s[j]+1,d[i][j][0]); cnt=max(cnt,MIN*MIN); } } for(int i=1;i<=n;++i){ memset(w,0,sizeof(w)); top=0; for(int j=1;j<=m;++j){ w[j]=j; while(top&&d[i][stack[top]][1]>d[i][j][1]) w[stack[top--]]=j-1; stack[++top]=j; } //while(top) w[stack[top--]]=n; memset(s,0,sizeof(s)); top=0; for(int j=m;j>=1;--j){ s[j]=j; while(top&&d[i][stack[top]][0]>d[i][j][1]) s[stack[top--]]=j+1; stack[++top]=j; } //while(top) s[stack[top--]]=1; for(int j=1;j<=m;++j){ ans=max(ans,(w[j]-s[j]+1)*d[i][j][1]); int MIN=min(w[j]-s[j]+1,d[i][j][1]); cnt=max(cnt,MIN*MIN); } } printf("%d %d",cnt,ans); return 0; }