洛谷 P5662 [CSP-J2019] 纪念品 题解
题目链接
题目大意
已知 \(N\) 个商品未来 \(T\) 天的价格,现在手上有 \(M\) 元钱,求 \(T\) 天后通过买卖商品最多能获得多少钱。
思路分析
首先,持有一个纪念品等同于每天买下这个纪念品,第二天卖出后再迅速买入,第三天卖出后再迅速买入……
证明过程
假设这个纪念品第 $i$ 天的价格为 $p_i$,则在第 $1$ 天至第 $n$ 天持有这一纪念品能赚 $p_n-p_1$ 元,而在每一天卖出后又迅速买入能赚 $$ \begin{aligned} \sum_{i=2}^{n}(p_i-p_{i-1})&=p_2-p_1+p_3-p_2+\cdots+p_n-p_{n-1} \\ &=p_n-p_1 \end{aligned} $$ 二者相等,所以可以替代所以我们可以从第 \(1\) 天遍历至第 \(T-1\) 天,每天对 \(N\) 个商品进行一次完全背包,对钱数 \(M\) 进行更新。
考虑动态规划。设 \(dp_i\) 表示第 \(i\) 天可以赚到的钱数,我们以物品当日的价格 \(p_{i,j}\) 作为重量,赚到的钱 \(p_{i+1,j}-p_{i,j}\) 为价值,所以状态转移方程为
\[dp_i=\max(dp_i,dp_{i-p_{i,j}}+p_{i+1,j}-p_{i,j})
\]
代码
注意 dp 时第 \(t\) 天无法买入了,所以外层循环 \(i\) 时只要循环至 \(T-1\) 即可。同时注意 \(m\) 在交易后会发生变化,需要及时更新。
#include<bits/stdc++.h>
using namespace std;
const int N=105,M=1e4+10;
int t,n,m;
int p[N][N],dp[M];
int main(){
scanf("%d%d%d",&t,&n,&m);
for (int i=1;i<=t;++i){
for (int j=1;j<=n;++j) scanf("%d",&p[i][j]);
}
for (int i=1;i<t;++i){
memset(dp,0,sizeof dp);
for (int j=1;j<=n;++j){
for (int k=p[i][j];k<=m;++k) dp[k]=max(dp[k],dp[k-p[i][j]]+p[i+1][j]-p[i][j]);
//完全背包模板
}
m+=dp[m];//因为获得的钱可以再用于交易,所以每天要更新 m
}
printf("%d",m);
return 0;
}

浙公网安备 33010602011771号