单调栈复习--最大01子矩阵 01矩阵统计全1矩阵数量

最大01子矩阵 例题:POJ3494

代码实现有些许复杂

#include<cstdio>
#include<stack>
using namespace std;
const int N=2e3+10;
int n,m,a[N][N],h[N][N],l[N][N],r[N][N];
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) h[i][j]=l[i][j]=r[i][j]=0;

        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                scanf("%d",&a[i][j]);
                if(a[i][j]) h[i][j]=h[i-1][j]+1;
            }
        }

        //预处理左区间

        for(int i=1;i<=n;++i){
            stack<int>sta;
            sta.push(0);
            h[i][0]=-1;
            for(int j=1;j<=m;++j) {

                if(h[i][j]==0) {
                    while(sta.size()) sta.pop();
                    sta.push(j);
                    continue;
                }
                if(h[i][j]>h[i][sta.top()]){
                     sta.push(j);
                     l[i][j]=j;
                     continue;
                }
                while(h[i][j]<=h[i][sta.top()]) sta.pop();
                l[i][j]=sta.top()+1;
                //printf("i:%d sz:%d\n",i,sta.size());
                sta.push(j);
            }
        }

        //预处理右区间
        //puts("***");
        for(int i=1;i<=n;++i){
            h[i][m+1]=-1;
            stack<int>sta;
            sta.push(m+1);
            for(int j=m;j>=1;--j){
                if(h[i][j]==0){
                    while(sta.size()) sta.pop();
                    sta.push(j);
                    continue;
                }
                if(h[i][j]>h[i][sta.top()]){
                    sta.push(j);
                    r[i][j]=j;
                    continue;
                }
                while(h[i][j]<=h[i][sta.top()]) sta.pop();
                r[i][j]=sta.top()-1;
                sta.push(j);
            }
        }

//        puts("h");
//        for(int i=1;i<=n;++i){
//            for(int j=1;j<=m;++j) printf("%d ",h[i][j]);
//            puts("");
//        }
//        puts("l");
//        for(int i=1;i<=n;++i){
//            for(int j=1;j<=m;++j) printf("%d ",l[i][j]);
//            puts("");
//        }
//         puts("r");
//        for(int i=1;i<=n;++i){
//            for(int j=1;j<=m;++j) printf("%d ",r[i][j]);
//            puts("");
//        }

        int ans=0;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(h[i][j])
                ans=max(ans,(r[i][j]-l[i][j]+1)*h[i][j]);
            }
        }
        printf("%d\n",ans);


    }
}
/*
5 5
0 1 0 1 0
1 1 0 1 0
1 1 1 1 1
1 1 1 1 1
0 0 0 0 0
*/

F-Animal Protection

做法:对于每个下表i 的贡献就是 (i-l[i]+1)*(r[i]-i+1)*h[i]  但是这样似乎有重复计算的,解决也很简单,就是预处理l[i]是保持严格递增,预处理r[i]是保持不递减就可以了。

#include<cstdio>
#include<stack>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
const int N=2e3+10;
int n,m,h[N][N],l[N][N],r[N][N];
char s[N][N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;++j){
            if(s[i][j]=='O') h[i][j]=h[i-1][j]+1;
        }
    }

    for(int i=1;i<=n;++i){
        stack<int>sta;
        sta.push(0);
        for(int j=1;j<=m;++j){
            if(h[i][j]==0){
                while(sta.size()) sta.pop();
                sta.push(j);
                continue;
            }
            if(h[i][j]>h[i][sta.top()]) {
                l[i][j]=j;
                sta.push(j);
                continue;
            }
            while(h[i][j]<h[i][sta.top()]) sta.pop();//注意这里是小于,下面求r是小于等于
            l[i][j]=sta.top()+1;
            sta.push(j);
        }
    }


    for(int i=1;i<=n;++i){
        stack<int>sta;
        sta.push(m+1);
        for(int j=m;j;--j){
            if(h[i][j]==0){
                while(sta.size()) sta.pop();
                sta.push(j);
                continue;
            }
            if(h[i][j]>h[i][sta.top()]) {
                r[i][j]=j;
                sta.push(j);
                continue;
            }
            while(h[i][j]<=h[i][sta.top()]) sta.pop();
            r[i][j]=sta.top()-1;
            sta.push(j);
        }
    }

    ll ans=0;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            ans=(ans+(r[i][j]-j+1)*(j-l[i][j]+1)%mod*h[i][j]%mod)%mod;
            //printf("i:%d j:%d %d\n",i,j,(r[i][j]-j+1)*(j-l[i][j]+1)%mod*h[i][j]%mod);
        }
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/106759415