P5662 [CSP-J2019] 纪念品
题目
点击查看题目
题目描述 小伟突然获得一种超能力,他知道未来 T 天 N 种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。 每天,小伟可以进行以下两种交易无限次: 1. 任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品; 2. 卖出持有的任意一个纪念品,以当日价格换回金币。 每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。 T 天之后,小伟的超能力消失。因此他一定会在第 T 天卖出所有纪念品换回金币。 小伟现在有 M 枚金币,他想要在超能力消失后拥有尽可能多的金币。 输入格式 第一行包含三个正整数 T, N, M,相邻两数之间以一个空格分开,分别代表未来天数 T,纪念品数量 N,小伟现在拥有的金币数量 M。 接下来 T 行,每行包含 N 个正整数,相邻两数之间以一个空格分隔。第 i 行的 N 个正整数分别为 P_{i,1},P_{i,2},……,P_{i,N},其中 P_{i,j} 表示第 i 天第 j 种纪念品的价格。 输出格式 输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。
分析
题目中说了,求在最后将所有纪念品卖掉后能拥有的最多金币数量。
那么我们就可以设 表示在第 天把所有纪念品都卖掉后能拥有的最多金币的数量。
由于对于第 天,卖出纪念品和买入纪念品的价格相同,因此,我们可以在第 天先将手上所有的纪念品都卖掉。然后利用与次日相同纪念品的价格差挑选最佳纪念品从中赚取利润(是的,这就叫中间商赚差价)。即可求出第 天初始得到的最大金币(这里指的也是在第 天将所有纪念品卖掉后的,即 )。
那么他的状态转移方程就是:
{}
还有变量无法表示出来,我们就将他加入状态转移方程中。(相信有聪明的小朋友已经看出来接下来就是标准的完全背包了)
表示用第 天把所有纪念品都卖掉后能拥有的最多金币花费元购买纪念品所能得到的最大价值。
花费的是第 天购买纪念品的价格,得到的价值为第 天卖出后得到的收益。
对于一个纪念品 。
第 天能得到的最多金币数为:
是第 天获得的最大金币数, 是第 天能得到的最多金币数。
写代码的过程中可以发现我们己经枚举了天数,且在状态转移方程中 丝毫不动,因此可以将其省略。
code
点击查看代码
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; int T,n,m; int dp[10005],val[105][1005]; 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",&val[i][j]); int ans=m; for(int t=1;t<T;t++){ memset(dp,0xcf,sizeof(dp)); dp[0]=0; for(int i=1;i<=n;i++){ for(int j=val[t][i];j<=ans;j++){ dp[j]=max(dp[j],dp[j-val[t][i]]+val[t+1][i]); } } int num=ans; for(int i=1;i<=num;i++) ans=max(ans,num-i+dp[i]); } cout<<ans<<endl; return 0; }
summary
通过这题,我们可以总结出,一题DP可以先将状态设为题目要求的东西,再列出状态转移方程。如果状态转移方程有些部分无法表示出来,就将他加入状态之中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!