【JZOJ4820】最大化

来源:互联网 发布:wifi无线传输软件 编辑:程序博客网 时间:2024/06/05 00:59

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 1000000000llusing 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;}
0 0
原创粉丝点击