NOIP普及组 纪念品 题解

NOIP普及组 2019

+++

纪念品

题目描述

小伟突然获得一种超能力,他知道未来 T 天 N种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。

每天,小伟可以进行以下两种交易无限次

  1. 任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;
  2. 卖出持有的任意一个纪念品,以当日价格换回金币。

每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。

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;
}
原文地址:https://www.cnblogs.com/scl0725/p/13943066.html