【小结】最大子矩阵/子段/01子矩阵问题

无言以对 ARC081F luoguP1169 棋盘制作 小结: 最大子段和问题: (一段序列选一段最大) 直接贪心考虑选还是不选,f[i]表示以I结尾的最大子段和,f[i]=max(f[i-1]+a[i],a[i]).(显然当f[i-1]<0时不选) 最大子矩阵问题: 求一个不固定数值的子矩阵,那么枚举上下横边n^2,然后如果询问数值总和最大,将这一竖列sum当做一个数字,然后一个最大子段和,如果询问面积,单调栈搞。 最大全1子矩阵 将原0/1数列转化为-->这一列的最长连续的1长度, 例如 0 0 1 0 1 1 0 1 1 就转化为了 0 0 1 0 1 2 0 2 3 然后这样我们O(n)枚举每一行,然后用长度最长*f[i][j]来更新答案就可以了,具体实现-->单调栈。 玉蟾宫bzoj3039(权限)code(01最大子矩阵板题):
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 1005;
int n,m;
char ss[maxn][maxn];
int f[maxn][maxn];
int ans;
int o[maxn];
int sta[maxn],top;
int l[maxn],r[maxn];
void solve() {
    top = 0; sta[0] = 0; //维护一个自底往上单增单调栈,这样就可以找到最靠左并且比自己小的位置
    for(int i=1;i<=m;i++) {
        while(top&&o[sta[top]]>=o[i]) top--;
        l[i] = sta[top] + 1;
        sta[++top] = i;
    } 
    top = 0; sta[0] = m+1;
    for(int i=m;i;i--) {
        while(top&&o[sta[top]]>=o[i]) top--;
        r[i] = sta[top] - 1;
        sta[++top] = i;
    }
    for(int i=1;i<=m;i++) {
        ans = max(ans,o[i]*(r[i]-l[i]+1));
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            scanf("%s",&ss[i][j]);
        }
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            if(ss[i][j]=='F') {
                f[i][j] = f[i-1][j] + 1;
            }
        }
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) o[j] = f[i][j];
        solve();
    }
    printf("%d",ans*3);
}
   
posted @ 2018-10-18 17:35  Newuser233  阅读(10)  评论(0)    收藏  举报