【洛谷P1169】[ZJOI2007]棋盘制作

棋盘制作

题目链接

这个题是[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\n%d\n",ans2,ans1); return 0; }

猜你喜欢

转载自www.cnblogs.com/yjkhhh/p/9415706.html