洛谷P1052 过河【线性dp】【离散化】

题目https://www.luogu.org/problemnew/show/P1052

题意:

青蛙要从0跳到超过$l$的地方,每一次可以跳$s$到$t$之间的任意数。

在河中有m个石头,要求在尽量不要跳到石头的情况下,青蛙最少可能会跳到多少颗石头。

思路:

刚开始很自然的想到就是用dp[i]表示跳到坐标i时最少要跳到多少时候,dp[i]可以用dp[i-(s~t)]转移过来。

但是一看数据范围,坐标最大是1e9,t是10,时间空间都不够。

再一看m范围才100,这种情况下就要想到用离散化。

因为跳的距离大于t和小于t其实是一样的。对于大于t的某数k,一定可以通过跳x次t步再跳k%t步到达k。

对于石头之间距离超过t的,都可以把中间的距离压缩至t~2t之间。

之所以不是0~t是因为,0~s之间的距离是跳不到的但是t~t+s是可以跳到的。他们并不等价。

然后再用上面说的dp就可以了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<set>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<cmath> 
 9 #include<stack>
10 #include<queue>
11 #include<iostream>
12 
13 #define inf 0x7fffffff
14 using namespace std;
15 typedef long long LL;
16 typedef pair<string, string> pr;
17 
18 int l, s, t, m;
19 const int maxn = 105;
20 int stone[maxn]; 
21 int dp[maxn * 20];
22 int vis[maxn * 20];
23 
24 int main()
25 {
26     scanf("%d%d%d%d", &l, &s, &t, &m);
27     for(int i = 1; i <= m; i++){
28         scanf("%d", &stone[i]);
29     }
30     stone[0] = 0;stone[m + 1] = l;
31     sort(stone, stone + 2 + m);
32     int far = 0;
33     for(int i = 1; i <= m + 1; i++){
34         if(stone[i] - stone[i - 1] > t){
35             far += (stone[i] - stone[i - 1]) % t + t;
36         }
37         else{
38             far += (stone[i] - stone[i - 1]);
39         }
40         vis[far] = 1;
41     }
42     vis[far] = 0;vis[0] = 0;
43     //cout<<far<<endl;
44     
45     memset(dp, 0x3f, sizeof(dp));
46     dp[0] = 0;
47     
48     for(int i = 1; i <= far + t - 1; i++){
49         for(int j = s; j <= t; j++){
50             if(i - j >= 0){
51                 dp[i] = min(dp[i], dp[i - j] + vis[i]);
52             }
53         }
54     }
55     
56     int ans = 500;
57     for(int i = far; i <= far + t - 1; i++){
58         ans = min(ans, dp[i]);
59     }
60     printf("%d\n", ans);
61     
62     return 0; 
63 }

猜你喜欢

转载自www.cnblogs.com/wyboooo/p/10858812.html