【每日一题】27. 过河 (DP + 离散化)

补题链接:Here

算法涉及:DP + 离散化

(l) 的范围太大,无法作为数组下标,所以先离散化,再DP。两点间的距离d大于t时,一定可以由 (d \% t) 跳过来,所以最多只需要t+d%t种距离的状态就可以表示这两个石子之间的任意距离关系。这样就把题目中的 (10^9) 压缩成了(2*t*m) 最多不超过 (2000) ,然后就可以放心大胆地用DP了。不过要注意题目中的“当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥”,所以DP的终点是一个范围而非确切的一个点,最后还要在这个范围内取最小值。

using ll = long long;
const int N = 1e6 + 10;
const ll inf = 0x3f3f3f3f;
ll dp[N], a[N], vis[N];
void solve() {
	int l, s, t, m;
	cin >> l >> s >> t >> m;
	for (int i = 1; i <= m; ++i)cin >> a[i];
	sort(a + 1, a + 1 + m);
	a[0] = 0, a[m + 1] = l;
	int tmp = 0;
	for (int i = 1; i <= m + 1; ++i) {
		//这里一定要在取模后加t,否则会WA
		if (a[i] - a[i - 1] > t)tmp += (a[i] - a[i - 1]) % t + t;
		else tmp += a[i] - a[i - 1];
		vis[tmp] = 1; //表示此处有石子
	}
	memset(dp, 0x3f, sizeof(dp));
	dp[0] = 0;
	for (int i = 1; i <= tmp + 100; ++i)
		for (int j = s; j <= t; ++j)
			if (i >= j)dp[i] = min(dp[i], dp[i - j] + vis[i]);
	ll ans = inf;
	//终点可能的范围,稍微写大点·
	for (int i = tmp; i <= tmp + 100; ++i)
		ans = min(ans, dp[i]);
	cout << ans;
}

The desire of his soul is the prophecy of his fate
你灵魂的欲望,是你命运的先知。

原文地址:https://www.cnblogs.com/RioTian/p/14773808.html