bzoj1057: [ZJOI2007]棋盘制作(悬线法)

  题目要求纵横坐标和奇偶性不同的点取值不同,于是我们把纵横坐标和奇偶性为1的点和0的点分别取反,就变成经典的最大全1子矩阵问题了,用悬线法解决。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
const int maxn=2010,inf=1e9;
int n,m,ans1,ans2;
int h[maxn],mp[maxn][maxn],l[maxn],r[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;                                                                                                                                                                        
}
int sqr(int x){return x*x;}
void dp()
{
    memset(h,0,(m+1)<<2);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        if(mp[i][j])h[j]++;else h[j]=0;
        for(int j=1;j<=m;j++)
        if(mp[i][j])
        for(l[j]=j;h[j]<=h[l[j]-1]&&mp[i][l[j]-1];l[j]=l[l[j]-1]);
        for(int j=m;j;j--)
        if(mp[i][j])
        for(r[j]=j;h[j]<=h[r[j]+1]&&mp[i][r[j]+1];r[j]=r[r[j]+1]);
        for(int j=1;j<=m;j++)
        ans1=max(ans1,(r[j]-l[j]+1)*h[j]);
        for(int j=1;j<=m;j++)
        ans2=max(ans2,min(sqr(r[j]-l[j]+1),sqr(h[j])));
    }
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    read(mp[i][j]),mp[i][j]=((i+j)&1?mp[i][j]:!mp[i][j]);
    dp();
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)mp[i][j]=!mp[i][j];
    dp();
    printf("%d\n%d",ans2,ans1);
    
}
View Code
posted @ 2017-09-07 19:35  Sakits  阅读(...)  评论(... 编辑 收藏