NOIP普及组 2019
+++
纪念品
题目描述
小伟突然获得一种超能力,他知道未来 T 天 N种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。
每天,小伟可以进行以下两种交易无限次:
- 任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;
- 卖出持有的任意一个纪念品,以当日价格换回金币。
每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。
TT 天之后,小伟的超能力消失。因此他一定会在第T 天卖出所有纪念品换回金币。
小伟现在有 M枚金币,他想要在超能力消失后拥有尽可能多的金币。
输入格式
第一行包含三个正整数 T, N, M,相邻两数之间以一个空格分开,分别代表未来天数 TT,纪念品数量N,小伟现在拥有的金币数量 M*。
接下来 T行,每行包含 N 个正整数,相邻两数之间以一个空格分隔。第 i* 行的 N* 个正整数分别为 P_{i,1}P**i,1,P_{i,2}P**i,2,……,P_{i,N}P**i,N,其中 P_{i,j}P**i,j 表示第 i* 天第 j* 种纪念品的价格。
输出格式
输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。
输入输出样例
输入 #1复制
6 1 100
50
20
25
20
25
50
输出 #1复制
305
分析:
首先很重要的一点就是,本题标注了物品可以当日购买,当日出售。因此这就简化了我们思考的难度,举个例子:我们可以把第一天购买第5天才卖的商品看作第二天出售再购买,第三天出售再购买直到第五天出售不购买。
所以基于上面的思路,我们不需要考虑隔天的销售情况,我们只需要考虑第二天的售买情况即可。
我们可以严格证明,如果每天都可以赚到最大,那么到第t天手中的金币一定是最多的,这就是我们贪心的策略。
我们把今天与明天各物品的价格差作为物品的价值,物品的原本价格看作物品的体积,我们就把本题转化为了完全背包问题,一共有t天,做t - 1次完全背包问题即可。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 110, M = 10010;
int w[N][N];
int f[M];
int t, n, 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", &w[i][j]);
for (int i = 1; i < t; i ++ )
{
memset(f, 0, sizeof f);//每次做dp前归零数组
for (int j = 1; j <= n; j ++ )
if (w[i + 1][j] > w[i][j]) //优化
for (int k = w[i][j]; k <= m; k ++ )
f[k] = max(f[k], f[k - w[i][j]] + w[i + 1][j] - w[i][j]);//优化后的完全背包模板
m += f[m];
}
printf("%d
", m);
return 0;
}