洛谷 P14460 【MX-S10-T1】『FeOI-4』寻雾启示 题解

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;
}
posted @ 2025-11-10 07:58  夢回路  阅读(5)  评论(0)    收藏  举报