P1052 过河

误操作害死人。。。。。。

题意:一只青蛙,在0--L上从0开始跳,每次可以跳[s,t]的距离

    给出一些石子的坐标,问从0跳到(跳过L)最少踩几颗石子

这是DP啊

好不容易想到

以f[i]代表跳到i时最少踩的石子数

然而  正当happy之时

TM数据范围$huge{L<=10^9!!!}$

。。。。。。。

后来看了题解

发现自己的思路是对的

L的范围太大,无法作为数组下标,所以先离散化,再DP。

两点间的距离d大于t时,一定可以由d%t跳过来,

所以最多只需要t+d%t种距离的状态就可以表示这两个石子之间的任意距离关系。

这样就把题目中的10^9压缩成了2*t*m最多不超过2000,

然后就可以放心大胆地用DP了。

不过要注意题目中的“当青蛙跳到或跳过坐标为L的点时,

就算青蛙已经跳出了独木桥”,所以DP的终点是一个范围而非确切的一个点,

最后还要在这个范围内取最小值。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std;
#define int long long 
int l,s,t;
int x[200];
int m;
int v[20500];
int f[20500];
int cnt;
int ans;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-f;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
inline void put(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        put(x/10);
    putchar(x%10+'0');
}
signed main()
{
    l=read();
    s=read();
    t=read();
    m=read();
    memset(f,0x7f,sizeof f);
    for(int i=1;i<=m;i++)
        x[i]=read();
    x[m+1]=l;
    sort(x+1,x+m+2);
    for(int i=1;i<=m+1;i++)
    {
        if(x[i]-x[i-1]>=t)
            cnt+=(x[i]-x[i-1])%t+t;
        else 
            cnt+=x[i]-x[i-1];
        v[cnt]=true;
    }
    v[cnt]=0;
    v[0]=0;
    f[0]=0;
    for(int i=1;i<=cnt+t-1;i++)
    {
        for(int j=s;j<=t;j++)
            if(i>=j)
                f[i]=min(f[i-j]+v[i],f[i]);
    }
    ans=0x7fffffff;
    for(int i=cnt;i<=cnt+t-1;i++)
        ans=min(ans,f[i]);
    put(ans);
    return 0;
}
原文地址:https://www.cnblogs.com/olinr/p/9425005.html