F. 纪念品 - 2023HBUCM程序设计竞赛/CSP-J2019
题面
小伟突然获得一种超能力,他知道未来
- 任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;
- 卖出持有的任意一个纪念品,以当日价格换回金币。 每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。
输入
第一行包含三个正整数
输出
输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。
题解
有限商品有限金钱,但每天可购入的商品都没有数量限制,一眼完全背包!……然而没写出来orz
纠结点:模板背包题中,物品同时具有两个属性:费用
本题破题关键点:当日购买的纪念品也可以当日卖出换回金币
这题题面有一句关键的话,“当日购买的纪念品也可以当日卖出换回金币”!这句话可以帮我们简化状态,因为如果一个纪念品,你想连续持有若干天,可以看做第一天买,第二天早上立刻卖掉,然后第二天买回来,第三天早上立刻卖掉,然后第三天买回来……所以我们就不需要记录每天手里持有多少纪念品了,统一认为我们今天买的纪念品,明天早上就立刻卖掉。明天又是新的一天,用所有的现金,进行新的决策就好了。
——P5662 纪念品 题解 - 泥土笨笨
所以本题中,商品的费用即为明天的价值 - 当天的价值,由此建立集合与状态转移方程:
集合:前
属性:要求最终拥有的最多金币数量,也是能赚到的最大差价,即为最大价值问题。
划分方案:
朴素方程:
但是本题的数据规模是
第一维天数在传递过程中只需要保留当天最大收益即可,所以可以优化掉;
第二维物品的优化参考完全背包问题即可。
#include<bits/stdc++.h> using namespace std; const int N = 105; int t, m, n; int v[N][N], w[N][N], f[N * N]; int main() { cin >> t >> n >> m; for (int i = 1; i <= t; i++) { for (int j = 1; j <= n; j++) { cin >> v[i][j]; w[i - 1][j] = v[i][j] - v[i - 1][j]; } } for (int d = 1; d < t; d++) { memset(f, 0, sizeof f); for (int i = 1; i <= n; i++) for (int j = v[d][i]; j <= m; j++) f[j] = max(f[j], f[j - v[d][i]] + w[d][i]); m += f[m]; } cout << m; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)