题意:
桥长度为$L$ ,分布有$n$ 个石子,青蛙每次可以跳 $[S,T]$ 的距离,问青蛙过桥至少要踩多少个石子。
$(1<=S,T<=10,m<=100,a_i<=10^9, a_i 表示第i个石子的位置)$
solution
这是个很显然的dp题,难点在于他的 $a_i$ 达到了 $10^9$ ,所以我们需要压缩一下。
- 当 $s==t$ 时,答案就是位置能被 $s$ 整除的石子个数。
- 当 $s!=t$ 时,我们可以发现:假设当前位置为 $x$ ,那么 $x+s*t$ 之后的所有位置是一定可以被走到的。(可以看做是 $s$ 个 $t$ 步相加或 $t$ 个 $s$ 步相加,然后调整某些步的长度即可。)
然后,石子之间的距离就被压缩了,只要相邻的两个石子距离 $>=st$ 的变成 $st$ 即可。
但是这样一压缩,最后的落点就不能确定了,但是起点是已知的,所以干脆倒过来dp。
状态转移方程:
- i 点有石子:$dp[i] = min(dp[i], dp[i+j]+1)$
- i 点无石子:$dp[i] = min(dp[i], dp[i+j])$
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int l, s, t, n, dis, res, a[N], dp[N], vis[N]; int main() { cin >> l >> s >> t >> n; for (int i = 1; i <= n; i++) cin >> a[i]; if (s == t) { for (int i = 1; i <= n; i++) { if (a[i] % s == 0) res++; } cout << res << '\n'; return 0; } sort(a + 1, a + n + 1); int len = s * t; for (int i = 1; i <= n; i++) { int d = a[i] - a[i - 1]; if (d > len) d = len; dis += d; vis[dis] = 1; } for (int i = dis; i >= 0; i--) { dp[i] = 100; for (int j = s; j <= t; j++) { dp[i] = min(dp[i], dp[i + j] + vis[i]); } } cout << dp[0] << '\n'; return 0; }
|