2017北京网赛 hihocoder #1580 : Matrix 【DP】

传送门


就像最大子矩阵和一样降维
先不考虑p
i,j,sum[k]=jx=imat[x][k]
sum[]

,minVal[k]=min(mat[x][k]|i<=x<=j)

d[i][0]=i,p
d[i][1]=i,p
d[i][0]=max(d[i1][0],0)+sum[i]
d[i][1]=max{d[i1][1]+sum[i],max(d[i1][0],0)+sum[i]minVal[i]+p}
当选择的行数量不是n行时
p,={max(d[i1][0],d[i1][1]) | 0<=i<n})

对于选择n行且选择了m列,此时必须要选一个值修改为p
方便起见对于选择了n行时,继续枚举选择的列的区间 O(n2)
复杂度 O(n3)

#include<stdio.h>
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define MEM(a,x) memset(a,x,sizeof(a))
#define lowbit(x) ((x)&-(x))

using namespace std;

const int INF = 1e9+7;
const int inf=INF;
const int N = 300 + 5;
int mat[N][N];
int sum[N];
int d[N][2];
int minVal[N];
int dp(int n,int*sum,int p){
    d[0][0]=sum[0];
    d[0][1]=sum[0]-minVal[0]+p;
    for(int i=1;i<n;++i){
        d[i][0]=max(d[i-1][0],0)+sum[i];
        d[i][1]=max( d[i-1][1]+sum[i], max(d[i-1][0],0)+ sum[i]-minVal[i]+p );
    }
    int ans=-inf;
    for(int i=0;i<n;++i){
        ans=max(ans,max(d[i][0],d[i][1]));
    }
    return ans;
}

int tePan(int m,int p){//选择了0~n-1行时
    int ans=-inf;
    for(int i=0;i<m;++i){
        int minX=inf;
        int sumX=0;
        for(int j=i;j<m;++j){
            minX=min(minX,minVal[j]);
            sumX+=sum[j];
            if(i==0&&j==m-1){
                ans=max(ans,sumX-minX+p);
            }
            else{
                int tsumX=max(sumX-minX+p,sumX);
                ans=max(ans,tsumX);
            }
        }
    }
    return ans;
}

int slove(int n,int m,int p){
    int ans=-inf;
    for(int i=0;i<n;++i){
        fill(sum,sum+m+1,0);
        fill(minVal,minVal+m+1,inf);
        for(int j=i;j<n;++j){
            for(int k=0;k<m;++k){
                sum[k]+=mat[j][k];
                minVal[k]=min(minVal[k],mat[j][k]);
            }
            if(i==0&&j==n-1){
                ans=max(ans,tePan(m,p));
            }
            else{
                ans=max(dp(m,sum,p),ans);
            }
        }
    }
    return ans;
}

int main(){
    //freopen("/home/lu/code/r.txt","r",stdin);
    //freopen("/home/lu/code/w.txt","w",stdout);
    int n,m,p;
    while(~scanf("%d%d%d",&n,&m,&p)){
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                scanf("%d",&mat[i][j]);
            }
        }
        printf("%d\n",slove(n,m,p));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值