题目: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 ", ans); 61 62 return 0; 63 }