题解 P1052 【过河】

1.30分做法(理论上只有30分)

实际上却有40分
首先我们看一下题意,可以 看出是线性dp

1.状态定义

我们要定义的状态肯定是在某种情况下的跳最少石子数,那么这个石子数与且只与目前的位置有关。

所以我们定义:dp[i]表示从1跳到第i个点的最小踩石子数。

2.转移方程

dp[i]可能从哪里来呢:它一定是从前面的某个状态转移来的,且它只与前面dp[j]的值、当前位置有无石子有关
我们枚举j,j表示上一步跳的距离,当然s<=j<=t。 stone[i]表示第i个位置有i个石子,i只为0,1
所以就是 dp[i]=min(dp[i],dp[i-j]+stone[i]);

3.枚举范围

这里提醒大家亿下,蒟蒻枚举时把i从1开始枚了,调了很久,应从s开始枚,因为i<s的点都不可能跳到,第一个可以跳到的是s

所以: i从s到l枚举,j从s到t枚举。

4.特判

题目中给的是“s<=t”所以s==t时,只有1种跳法,所以无论你怎么跳。答案都固定,就是 q[i]表示第i块石子的位置,如果q[i]是s的倍数;这颗石子就必须要踩

5.答案(坑)

因为青蛙可能跳到大于l的位置(但小于l+t),因为题目中的叙述“当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥” 所以输出dp[l]是错的,应输出min(dp[i~n+t-1]); 下面就是反例 l=7,答案存在dp[8]中。 应输出0, 如果输出dp[7]会输出inf。 7 4 5 1 5

1_2_3_4_5(石头)_6_7---8

为什么不画个图呢?当然是因为懒啊

这里dp[8]里存的才是答案,因为从4不可能到7


code:

#include<bits/stdc++.h>
using namespace std;
int l,s,t,m,stone[10000001],p,dp[1000001],q[101];
int main()
{
    cin>>l>>s>>t>>m;
    for(int i=1;i<=m;++i)
        cin>>q[i];
    if(s==t) 
    {
        int s=0;
        for(int i=1;i<=m;++i)
        if(q[i]%t==0) s++;
        cout<<s;
        return 0;
    }//特判
    sort(q+1,q+m+1);
    for(int i=1;i<=m;++i)
    {
        p+=q[i]-q[i-1];
        stone[p]=1;
    }
    dp[0]=0;memset(dp,0x3f,sizeof(dp));
    for(int i=s;i<=p+9;++i)
      for(int j=s;j<=t;++j)
        {
            dp[i]=min(dp[i],dp[i-j]+stone[i]);
        }  
    int ans=0x7fffffff;
    for(int i=p;i<=p+t;++i)
      ans=min(ans,dp[i]);
     cout<<ans; 
return 0;
}

100 分做法

看了看难度,啊呸数据范围:l<=10^9 ??? 这题一定不只是一个线性dp。

如果用线性dp,复杂度约为O(n*(s-t)) 也就是O(10n),不仅会T,
你还要开一个10^9的数组

路径压缩

读一读题,就会发现桥上的石子分布是很稀疏的,平均每10^8才会有一块,所以我们就把两颗石子多余某数的距离化为某数。
这个“某数”一定是j的倍数,这样就相当于可以给青蛙一个休息,缓一缓的距离。(只可意会不可言传)
又因为j要大于等于1,小于等于10(1<=s,t<=10)
所以“某数”为1~10的最小公倍数:2520
只用在读入后求stone数组时把距离取 min(距离,2520)就可以辣。


code:

#include<bits/stdc++.h>
using namespace std;
int l,s,t,m,stone[252010],p,dp[252010],q[101];//stone数组的252010 就约是每两格的距离最大值2520*格数最大值99  
int main()
{
    cin>>l>>s>>t>>m;
    for(int i=1;i<=m;++i)
        cin>>q[i];
    if(s==t) 
    {
        int s=0;
        for(int i=1;i<=m;++i)
        if(q[i]%t==0) s++;
        cout<<s;
        return 0;
    }//特判 
    sort(q+1,q+m+1);//不排序会RE 
    for(int i=1;i<=m;++i)
    {
        p+=min(q[i]-q[i-1],2520);
        stone[p]=1;
    }
    dp[0]=0;memset(dp,0x3f,sizeof(dp));
    for(int i=s;i<=p+9;++i)
      for(int j=s;j<=t;++j)
        {
            dp[i]=min(dp[i],dp[i-j]+stone[i]);
        }  
    int ans=0x7fffffff;
    for(int i=p;i<=p+t;++i)
      ans=min(ans,dp[i]);
     cout<<ans; 
return 0;
}
posted @ 2020-07-26 00:07  寂静的海底  阅读(4)  评论(0编辑  收藏  举报  来源