棋盘制作
这个题是[USACO5.3]巨大的牛棚Big Barn和玉蟾宫的结合
一道顶两道毒瘤!
题解:
首先,棋盘有两种选法:
1.任意白格(x,y) (x+y)%2=0 ,任意黑格(x,y) (x+y)%2=1
2.任意白格(x,y) (x+y)%2=1 ,任意黑格(x,y) (x+y)%2=0
那么我们可以先将所有(x+y)%2=1的格子颜色取反,
就变成了求最大的颜色都为1的正方形和矩形
再把整个棋盘取反,求一遍最大正方形和矩形
正方形:dp[i][j]表示以(i,j)为右下角的最大正方形的边长
if(dp[i][j]==1) dp[i][j]=min(dp[i][j],min(dp[i-1][j],dp[i][j-1]));
矩形:high[i][j]表示格子(i,j)及上面连续1的长度,枚举i,每次跑一遍单调队列
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define reset(a) memset(a,0,sizeof(a)) #define N 2010 int n,m,dp[N][N],ans1,ans2; int f[N][N],len[N],stack[N],top; bool map[N][N]; inline bool read(){ char c=getchar(); while(c!='0'&&c!='1') c=getchar(); return c-'0'; } inline int min(int x,int y){ return x<y?x:y; } inline int max(int x,int y){ return x>y?x:y; }
void work(){ bool x; int u; for(int i=1;i<=n;i++,top=0) for(int j=1;j<=m+1;j++){ len[j]=u=0; if(j!=m+1) { x=map[i][j]; if(map[i][j]){ f[i][j]=u=f[i-1][j]+1; dp[i][j]=min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1]))+1; } ans2=max(ans2,dp[i][j]*dp[i][j]); } while(top&&u<=f[i][stack[top]]){ len[j]+=len[stack[top]]; ans1=max(ans1,f[i][stack[top]]*len[j]); top--; } len[j]++; stack[++top]=j; } } inline void init(){ reset(f); reset(dp); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) map[i][j]^=1; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ map[i][j]=read(); if((i+j)%2) map[i][j]^=1; } work(); init(); work(); printf("%d %d ",ans2,ans1); return 0; }