1. 程式人生 > >2017北京網賽 hihocoder #1580 : Matrix 【DP】

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; }