bzoj 1057 单调栈

首先我们可以枚举每个一点,然后向下一直拓展到不能拓展为止,然后向下拓展的同时我们可以算出来向左最多拓展的个数,用单调栈来维护一个上升的序列,这样就类似与悬线法找最大01子矩阵了,但是对于这题01交替来说,好多细节比较麻烦,所以我们可以采用另一种转换方法,对于一个01矩阵来说,一定满足一下两个条件中的一个:

  1:矩阵中所有0的点(i,j),i与j的奇偶相同,且对于所有1点(i,j),i与j的奇偶不同。

  2:矩阵中所有0的点(i,j),i与j的奇偶不同,且对于所有1点(i,j),i与j的奇偶相同。

  那么我们把所有满足1条件的点标号为1,满足2条件的点标号为0,这样,我们就求出标号矩阵的01子矩阵就行了,还是使用单调栈的方法求,但是这里的最大0矩阵和最大1矩阵都有可能成为答案,所以我们先求最大1矩阵,然后将矩阵取非(!),在求一遍更新答案就好了。

  至于正方形和矩形的求法是相同的,只是更新答案的方式不同,特别的,最大子方阵也可以用DP来求解,设w[i][j]为以(i,j)点为右下角的方阵的最大边长(面积),转移为w[i][j]=min(w[i-1][j-1],w[i][j-1],w[i-1][j])+1。

  反思:没有考虑到DP的方阵局限性。

/**************************************************************

    Problem: 1057

    User: BLADEVIL

    Language: C++

    Result: Accepted

    Time:2948 ms

    Memory:48168 kb

****************************************************************/

 

//By BLADEVIL

#include <cstdio>

#include <algorithm>

#define maxn 2010

#define sqr(x) x*x

 

using namespace std;

 

int a[maxn][maxn],w[maxn],s[maxn],f[maxn][maxn],map[maxn][maxn];

int top,n,m,ans1,ans2;

 

void calc()

{

    for (int j=1;j<=m;j++)

    {

        top=0;

        for (int i=1;i<=n;i++)

        {

            int minw=i;

            while (top&&s[top]>=f[i][j])

            {

                ans1=max(ans1,s[top]*(i-w[top]));

                ans2=max(ans2,sqr(min(s[top],i-w[top])));

                minw=w[top--];

            }

            s[++top]=f[i][j]; w[top]=minw;

        }

    }

 

}

 

int main()

{

    scanf("%d%d",&n,&m);

    for (int i=1;i<=n;i++)

        for (int j=1;j<=m;j++) 

        {

            scanf("%d",&a[i][j]);

            if ((i&1)==(j&1)&&a[i][j]||(i&1)!=(j&1)&&!a[i][j]) map[i][j]=1; else map[i][j]=0;

        }

    for (int i=1;i<=n;i++)

        for (int j=1;j<=m;j++)

            if (map[i][j]) f[i][j]=f[i][j-1]+1; else f[i][j]=0;

    calc();

    for (int i=1;i<=n;i++)

        for (int j=1;j<=m;j++)

            map[i][j]=!map[i][j];

    for (int i=1;i<=n;i++)

        for (int j=1;j<=m;j++)

            if (map[i][j]) f[i][j]=f[i][j-1]+1; else f[i][j]=0;

    calc();

    printf("%d\n%d\n",ans2,ans1);

    return 0;

}

 

 

你可能感兴趣的:(ZOJ)