成为王的痛苦(前缀最大优化dp)

传送门

D. 成为王的痛苦 Problem 4584  ] Discussion ]


Description

“拔出石中剑,你便是王”。
“拔剑之前,你最好先想一想。因为一旦拔起剑,你将不再是人类,你会被所有人类憎恶,你将最终迎来悲剧的死亡。”魔术师梅林如是说。
然而名为Arturia Pendragone的少女还是拔起了剑,成为了英格兰之王。
一天,王发现她拔出的石中剑上有NN个凹槽,经过多年征战,她一共收集了MM块宝石,并且NMN≥M。将每块宝石放到每一个凹槽中都会使石中剑具有一定的美丽值(可能为负数)。
1i<jM1≤i<j≤M,则编号为ii的宝石所在的凹槽的编号一定要小于编号为jj的宝石所在的凹槽的编号。
由于王也是女孩子,所以她希望这个美丽值最大。
当然,每个凹槽只能放入一 块宝石,每块宝石也只能放入一个凹槽。
每块宝石都必须被使用到。

Input

第一行,两个整数N,MN,M;
接下来MM行,每行NN个整数,表示这一块宝石放入这一个凹槽的美丽值。

Output

一行,表示美丽值的最大可能值。

Samples

Input Copy
3 2
-10 10 10
0 30 10
Output
20

Hint

【数据范围】

  • 对于10%的数据,M=1M=1
  • 另外20%的数据,1M51≤M≤5  MN20M≤N≤20
  • 对于100%的数据,1MN15001≤M≤N≤1500

每个宝石的美丽值保证大于105−105,小于105105

Source

石光中学 2018 常州 普及组 day6
 
题目大意:
m行n列的矩阵,从一行开始每一行可以选择一个位置的权值
但是如果第一行选择的第j列的位置
那么再往下选的时候只能选大于j 列的列
 
 
 
 
解题思路:
dp[i][j]代表的是前i行选择最后选择第j列的最大值,所以转移方程有dp[i][j]=max(dp[i][j],dp[i-1][k]+a[i][j],但是这样的话要三层for,会超时的
 
优化方案:
可以用前缀的最大值,对于第i行你只是需要的是上一行中的最大值
其中p[j]代表的是前j行的最大值
所以优化完之后就是
 
for(int i=1;i<=n;i++){
    for(int j=i;j<=m;j++){//第i行最少已经取了i-1个
        dp[i][j]=max(dp[i][j],p[j-1]+a[i][j]);
    }
    p[i]=dp[i][i];//更新最大值值
    for(int j=i+1;j<=m;j++){
        p[j]=max(p[j-1],dp[i][j]);
    }
}

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=3e3+100;
const int INF=0x3f3f3f3f;
int n,m;
int a[maxn][maxn];
int dp[maxn][maxn];//dp[i][j]代表的是以第i行以j列结尾的最大值 
int p[maxn];
int main(){
    cin>>m>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            dp[i][j]=-INF;
        } 
    } 
    for(int i=1;i<=n;i++){
        for(int j=i;j<=m;j++){
            dp[i][j]=max(dp[i][j],p[j-1]+a[i][j]);
        }
        p[i]=dp[i][i];
        for(int j=i+1;j<=m;j++){
            p[j]=max(p[j-1],dp[i][j]);
        }
    }
    int ma=-INF;
    for(int i=1;i<=m;i++){
        ma=max(ma,dp[n][i]);
    }
    cout<<ma<<endl;
} 

 

 
 
posted @ 2021-01-27 17:04  哎呦哎(iui)  阅读(72)  评论(0编辑  收藏  举报