问题本质
看似复杂的多天多物品交易问题,核心转化为 T−1 轮完全背包。
思路分析
关键洞察:相邻天拆分
因为同一天可以先卖后买,所以持有一个物品从第 1 天到第 3 天,等价于:
> 第 1 天买 → 第 2 天卖 → 第 2 天立刻买回 → 第 3 天卖
中间那次"卖了又买"净收益为 0,不影响结果。因此:
> 跨多天的持有,可以拆成若干"相邻两天"的独立交易。
转化为完全背包
对于每一对相邻天 (i,i+1)(i, i+1)(i,i+1),问题变成:
* 背包容量 = 当前金币数 M
* 物品 j:
* 花费(买入价)= P[i][j]P[i][j]P[i][j]
* 收益(利润)= P[i+1][j]−P[i][j]P[i+1][j] - P[i][j]P[i+1][j]−P[i][j](仅当 > 0 时有意义)
* 每种物品可以买无限个 → 完全背包
* 做完一轮背包后,M += 最大利润,进入下一天
样例 1 验证
6 天 1 种纪念品,M=100,价格:50, 20, 25, 20, 25, 50
相邻天 买入价 卖出价 利润 操作 1→2 50 20 −30 不买 2→3 20 25 +5 买 5 个,赚 25,M=125 3→4 25 20 −5 不买 4→5 20 25 +5 买 6 个(花 120),赚 30,M=155 5→6 25 50 +25 买 6 个(花 150),赚 150,M=305
wait — 让我重新用背包思路逐步算:
* 初始 M=100
* 第 2→3 天:容量 100,物品花费 20 利润 5 → 买 5 个赚 25 → M=125
* 第 4→5 天:容量 125,物品花费 20 利润 5 → 买 6 个赚 30(剩 5 coin)→ M=155
* 第 5→6 天:容量 155,物品花费 25 利润 25 → 买 6 个赚 150(剩 5 coin)→ M=305
代码(逐行注释版)
复杂度
* 时间:O(T×N×Mmax)O(T \times N \times M_{max})O(T×N×Mmax ),最坏 100×100×10000=108100 \times 100 \times 10000 = 10^8100×100×10000=108,每步仅比较和加法,C++ 1s 可过
* 空间:O(Mmax)O(M_{max})O(Mmax ) = 10001 个 int ≈ 40KB
核心要点速记
> 本题的精髓是两步转化:
> 1. 多天 → 相邻两天:因为同天可卖可买,跨天持有可拆成逐天交易
> 2. 相邻两天交易 → 完全背包:花费 = 今天买入价,价值 = 明天卖出利润,每种可买无限个
>
> 完全背包 vs 0-1 背包的区别只在遍历方向:
> * 0-1 背包(每种 1 个)→ 倒序
> * 完全背包(每种无限)→ 正序
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------