传送门
D. 成为王的痛苦 [ Problem 4584 ] [ Discussion ]
Description
“拔出石中剑,你便是王”。
“拔剑之前,你最好先想一想。因为一旦拔起剑,你将不再是人类,你会被所有人类憎恶,你将最终迎来悲剧的死亡。”魔术师梅林如是说。
然而名为Arturia Pendragone的少女还是拔起了剑,成为了英格兰之王。
一天,王发现她拔出的石中剑上有NN个凹槽,经过多年征战,她一共收集了MM块宝石,并且N≥MN≥M。将每块宝石放到每一个凹槽中都会使石中剑具有一定的美丽值(可能为负数)。
若1≤i<j≤M1≤i<j≤M,则编号为ii的宝石所在的凹槽的编号一定要小于编号为jj的宝石所在的凹槽的编号。
由于王也是女孩子,所以她希望这个美丽值最大。
当然,每个凹槽只能放入一 块宝石,每块宝石也只能放入一个凹槽。
每块宝石都必须被使用到。
Input
第一行,两个整数N,MN,M;
接下来MM行,每行NN个整数,表示这一块宝石放入这一个凹槽的美丽值。
Output
一行,表示美丽值的最大可能值。
Samples
Hint
【数据范围】
- 对于10%的数据,M=1M=1
- 另外20%的数据,1≤M≤51≤M≤5 M≤N≤20M≤N≤20
- 对于100%的数据,1≤M≤N≤15001≤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; }