luogu 1169 [ZJOI2007]棋盘制作 悬线dp
悬线法,虽然得不到局部最优解,但是一定能得到全局最优解的算法,十分神奇~
#include <cstdio> #include <algorithm> #define N 2003 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,m,ans1,ans2; int v[N][N],l[N][N],r[N][N],up[N][N],len[N][N]; int main() { int i,j; // setIO("input"); scanf("%d%d",&n,&m); for(i=1;i<=n;++i) { for(j=1;j<=m;++j) scanf("%d",&v[i][j]),l[i][j]=r[i][j]=j, up[i][j]=1,len[i][j]=1; } for(i=1;i<=n;++i) { for(j=2;j<=m;++j) if(v[i][j]!=v[i][j-1]) l[i][j]=l[i][j-1]; for(j=m-1;j>=1;--j) if(v[i][j]!=v[i][j+1]) r[i][j]=r[i][j+1]; } for(i=1;i<=n;++i) { for(j=1;j<=m;++j) { if(i>1 && v[i][j]!=v[i-1][j]) { l[i][j]=max(l[i][j], l[i-1][j]); r[i][j]=min(r[i][j], r[i-1][j]); up[i][j]=up[i-1][j]+1; } ans1=max(ans1, up[i][j]*(r[i][j]-l[i][j]+1)); } } for(i=1;i<=n;++i) { for(j=1;j<=m;++j) { if(i>1&&j>1&&v[i][j]!=v[i][j-1]&&v[i][j]!=v[i-1][j]&&v[i][j]==v[i-1][j-1]) { len[i][j]=min(len[i][j-1], min(len[i-1][j], len[i-1][j-1]))+1; } } } for(i=1;i<=n;++i) { for(j=1;j<=m;++j) ans2=max(ans2, len[i][j]*len[i][j]); } printf("%d\n%d\n",ans2,ans1); return 0; }