luogu2331
P2331 [SCOI2005]最大子矩阵
题目描述
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
输入格式
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
输出格式
只有一行为k个子矩阵分值之和最大为多少。
输入输出样例
输入 #1
3 2 2
1 -3
2 3
-2 3
输出 #1
View Code
9
sol:dp[i][j][k]表示第一行匹配到i,第二行匹配到j,用了k个矩阵的最大值,XJB转移即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();} while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();} return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) {putchar('-'); x=-x;} if(x<10) {putchar(x+'0'); return;} write(x/10); putchar((x%10)+'0'); } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int N=105,M=15,inf=0x3f3f3f3f; int n,m,c,ans=-inf; int a[N][3],S[4][N],st[4][N][11]; int dp[N][N][M]; inline int cmin(int o,int a,int b) { return (S[o][a]<S[o][b])?a:b; } inline int ask(int o,int l,int r) { int oo=log2(r-l+1); return cmin(o,st[o][l][oo],st[o][r-(1<<oo)+1][oo]); } inline void Solve() { int i,j,k; memset(dp,-63,sizeof dp); dp[0][0][0]=0; for(i=1;i<=n;i++) { for(j=1;j<=c;j++) { for(k=0;k<=i-1;k++) { dp[i][0][j]=max(dp[i][0][j],dp[k][0][j-1]+S[1][i]-S[1][ask(1,k,i-1)]); dp[i][0][j]=max(dp[i][0][j],dp[k][0][j]); } } } for(i=1;i<=n;i++) ans=max(ans,dp[i][0][c]); Wl(ans); } int main() { freopen("data.in","r",stdin); int i,j,k,l; R(n); R(m); R(c); S[1][0]=S[2][0]=S[3][0]=0; for(i=1;i<=n;i++) { S[m+1][i]=S[m+1][i-1]; for(j=1;j<=m;j++) { S[j][i]=S[j][i-1]+(a[i][j]=read()); S[m+1][i]+=a[i][j]; } } for(k=1;k<=m+1;k++) { for(j=0;j<=n;j++) st[k][j][0]=j; for(i=1;i<=7;i++) { for(j=0;j+(1<<i)-1<=n;j++) st[k][j][i]=cmin(k,st[k][j][i-1],st[k][j+(1<<(i-1))][i-1]); } } if(m==1) {Solve(); return 0;} // for(i=0;i<=n;i++) cout<<S[1][i]<<' '<<S[2][i]<<' '<<S[3][i]<<endl; // for(i=0;i<=n;i++) for(j=i;j<=n;j++) // { // cout<<i<<" "<<j<<":"<<S[1][ask(1,i,j)]<<" "<<S[2][ask(2,i,j)]<<" "<<S[3][ask(3,i,j)]<<endl; // } memset(dp,-63,sizeof dp); dp[0][0][0]=0; for(i=0;i<=n;i++) for(j=0;j<=n;j++) for(k=1;k<=c;k++) { if(i==0&&j==0) continue; for(l=0;l<=i-1;l++) { dp[i][j][k]=max(dp[i][j][k],dp[l][j][k-1]+S[1][i]-S[1][ask(1,l,i-1)]); dp[i][j][k]=max(dp[i][j][k],dp[l][j][k]); } for(l=0;l<=j-1;l++) { dp[i][j][k]=max(dp[i][j][k],dp[i][l][k-1]+S[2][j]-S[2][ask(2,l,j-1)]); dp[i][j][k]=max(dp[i][j][k],dp[i][l][k]); } if(i==j) for(l=0;l<=i-1;l++) { dp[i][j][k]=max(dp[i][j][k],dp[l][l][k-1]+S[3][i]-S[3][ask(3,l,i-1)]); dp[i][j][k]=max(dp[i][j][k],dp[l][l][k]); } } // cout<<dp[1][1][1]<<' '<<dp[2][2][1]<<' '<<dp[2][2][2]<<' '<<dp[3][3][2]<<endl; for(i=1;i<=n;i++) for(j=1;j<=n;j++) ans=max(ans,dp[i][j][c]); Wl(ans); return 0; }
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!