Link
可做题。
考虑怎么做划算?要么在第 \(0\) 格等待全部铁锭满足之后购买并走到终点,要么重复一个买、走、折返、买、走这样的过程,注意到这个等待时间和行走路程都是可以二分的,但是神秘贪心好像都被毙掉了。
要输出 \(d\) 天的所有方案?考虑写一个 DP 状物。\(O(Tm^2)\) 的做法是容易想到的,按照上上述描述裸的模拟一下就可以了,记 \(f_i\) 表示搭建到第 \(i\) 格的最小代价:
\[f_{i} = \min \begin{cases}
(k + t_1)i \\
\min_{1 \leq j \leq i} \{ (f_j + 2 \times j \times t_2 + \max(0, ik - (f_j + j \times t_2)) + (i - j) \times t_1) \}
\end{cases}
\]
这个东西好像没有办法怎么优化?也没有可以套的 DS 来维护,观察, 但是对于每个 \(i\) 输出答案对应的 \(j\) 会发现 \(j\) 单调不降,记录上一个转移点 \(lst\) 并 DP。
卡 long long。
#include <bits/stdc++.h>using i64 = long long;void solve() {int m, k, t1, t2;std::cin >> m >> k >> t1 >> t2;std::vector<i64> dp(m + 1);int lst = 0;for (int i = 1; i <= m; i++) {dp[i] = 1ll * i * (k + t1);for (int j = std::max(lst, 1); j < i; j++) {i64 _f = dp[j] + (i64) 2 * j * t2 + std::max(0ll, 1ll * i * k - (dp[j] + 1ll * j * t2)) + 1ll * (i - j) * t1;if (_f < dp[i]) {dp[i] =_f;lst = j;} else {break;}}std::cout << dp[i] << " ";}std::cout << "\n";
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int t;std::cin >> t;while (t--) {solve();}return 0;
}