【JZOJ4820】最大化

Description

给出一个 n×m 的矩阵,求一个最大子矩阵,使得矩阵中的权值和大于0。输出最大子矩阵的面积。

Solution

枚举上界和下界,中间的一段压成一个序列。我们设 si 表示序列 [1,i] 的权值和。

如果 i<j<k(si<sj<sk) ,显然 j 是冗余的。

那么我们找出单调下降的si编号,然后倒着枚举右边界,然后左边界显然可以用指针维护(因为左边界向右移肯定没当前答案优)。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 301
#define ll long long
#define inf 1000000000ll
using namespace std;
ll a[N][N],b[N][N];
ll sum(int x1,int y1,int x2,int y2)
{
    return b[x2][y2]-b[x2][y1-1]-b[x1-1][y2]+b[x1-1][y1-1];
}
int n,m;
ll s[N];
int dl[N];
ll qq;
int main()
{
    freopen("max.in","r",stdin);
    freopen("max.out","w",stdout);
    cin>>n>>m;
    fo(i,1,n)
    fo(j,1,m)
    {
        scanf("%lld",&a[i][j]);
        b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j];
    }
    int ans=0;
    fo(u,1,n)
    fo(d,u,n)
    {
        int tot=0;
        s[0]=inf;
        fo(i,1,m)
        {
            ll qq=sum(u,1,d,i);
            s[i]=qq;
            if(s[dl[tot]]>qq) dl[++tot]=i;
        }
        int j=tot;
        fd(i,m,1)
        {
            while(dl[j]>=i) j--;
            if(s[i]>0)
            {
                ans=max(ans,(d-u+1)*i);
                break;
            }
            while(s[dl[j]]<s[i] && j) j--;
            j++;
            if(s[dl[j]]<s[i] && dl[j]<i) ans=max(ans,(d-u+1)*(i-dl[j]));
        }
    }
    cout<<ans;
}
posted @ 2016-10-15 16:45  sadstone  阅读(46)  评论(0编辑  收藏  举报