Question:


青蛙从桥头跳过独木桥,跳过就行,桥长为图片说明 ,青蛙跳过的路程图片说明 只要大于等于图片说明 就行。桥上有一些石头,题目会给石头的数量m和m个石头的位置,还有青蛙跳跃的最小距离s、最大距离t。
图片说明


Analysis:


离散化+dp。
这个离散化和我学过的不一样,我之前学的离散化是把一个大的集合向一个小的集合映射,而这题的离散化是省去不必要的距离,缩小区间。
如果图片说明 那么很简单,只有一条路径,没得选择,统计踩到多少石头就行,图片说明 表示会踩到这个石头,图片说明 是石头的位置。
图片说明 就要考虑离散化了:(p和t只是为了证明,和题目无关)
1.假设每次走图片说明图片说明 步。
2.图片说明 ,也就是图片说明图片说明 一定是互质的。
3.可以知道图片说明 有整数解,也可得图片说明 也是一定有解的。
4.设3的解为:图片说明
5.最后可以得到当图片说明 时,图片说明 有两个非负整数解,具体原理可以去看看扩展欧几里得解的情况。
6.根据5可以知道每次走图片说明图片说明 步,图片说明 步及其之后的地方都可以走到,所以接下来就可以愉快的离散化了。
7.这里p 看成是题目输入的图片说明 ,也就是说如果两点之间的距离大于图片说明 都可以直接缩小为图片说明
8.具体一点就是把图片说明 个石头和起点、终点看成图片说明 个点,他们之间的距离和就是离散化后桥的长度,因为离散化后桥的长度最大为图片说明 ,也就是9000,所以可以用数组stone标记离散化后石头的位置。第一个石头的位置是它和起点离散化后的距离,第二个石头的位置是它和第一个石头离散化后的距离加上前面一个石头的位置,其它的石头的位置也是这么算的。
9.因为可以跳出独木桥,所以答案要在图片说明 之间找,图片说明 是离散化后桥的长度,为什么不是图片说明 呢,因为到了终点就不用再跳了。
10.因为图片说明 小于等于90,所以写代码时我都是用90代替它。


Code:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
template <class T>
inline void read(T &res) {
    char c; T flag = 1;
    while ((c = getchar()) < '0' || c > '9')
        if (c == '-')
            flag = -1;
    res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9')
        res = res * 10 + c - '0';
    res *= flag;
}
int dis[105],a[105],stone[maxn],f[maxn],p;//局部变量的值都是0 
int main() {
    int l,s,t,m;
    read(l);
    read(s),read(t),read(m);
    if(s==t) {
        int pos,cnt=0;
        for(int i=1;i<=m;++i){
            read(pos);
            cnt+=(pos%s==0);
        }
        printf("%d\n",cnt);
        return 0;
    }
    for(int i=1;i<=m;++i)    read(a[i]);
    sort(a+1,a+1+m);
    for(int i=1;i<=m;++i) {
        dis[i]=min(a[i]-a[i-1],90);//a[0]等于0,也就是起点 
        p+=dis[i];
        stone[p]=1;
    }
    dis[m+1]=min(l-a[m],90);
    p+=dis[m+1];
    for(int i=1;i<=p+9;++i) {
        f[i]=0x3f3f3f3f;
        for(int j=s;j<=t;++j) if(i>=j)
        f[i]=min(f[i],f[i-j]+stone[i]);
    }
    int ans=0x3f3f3f3f;
    for(int i=p;i<=p+9;++i) ans=min(ans,f[i]);
    printf("%d\n",ans);
}