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
9

sol:dp[i][j][k]表示第一行匹配到i,第二行匹配到j,用了k个矩阵的最大值,XJB转移即可
#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;
}
View Code

 

 
posted @ 2019-07-26 20:50  yccdu  阅读(107)  评论(0编辑  收藏  举报