【每日一题】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;
}

posted @ 2021-05-16 14:36  Koshkaaa  阅读(55)  评论(0编辑  收藏  举报