过河 [HNOI2008,Codevs1105]

来源:互联网 发布:ubuntu输入密码后卡住 编辑:程序博客网 时间:2024/06/10 00:58

题目地址请点击——


过河


Description

在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。
在桥上有一些石子,青蛙很讨厌踩在这些石子上。
由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:01,……,L(其中 L 是桥的长度)。
坐标为 0 的点表示桥的起点,坐标为 L 的点表示桥的终点。
青蛙从桥的起点开始,不停的向终点方向跳跃。
一次跳跃的距离是 ST 之间的任意正整数(包括 S , T)。
当青蛙跳到或跳过坐标为 L 的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度 L,青蛙跳跃的距离范围 S , T,桥上石子的位置。
你的任务是确定青蛙要想过河,最少需要踩到的石子数。


Input

输入第一行有一个正整数 L1<=L<=109),表示独木桥的长度。
第二行有三个正整数 STM,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中 1ST101M100
第三行有 M 个不同的正整数分别表示这 M 个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。
所有相邻的整数之间用一个空格隔开。


Output

输出只包括一个整数,表示青蛙过河最少需要踩到的石子数。


Sample Input

10
2 3 5
2 3 5 6 7


Sample Output

2


Data Size & Hint

对于 30% 的数据,L<=10000
对于全部的数据,L<=109


Solution

fi=j=stf(ij)+?1:0

S<T,事实上对于某个可跳步长区间 [S,T],必然存在一个 MaxK 使得任何 kMaxK,都可以从一端正好跳到另一端。
题设中 1<=S<=T<=10,经过简单推导或者程序验证就可以发现,取 MaxK=100 就能满足所有区间。
于是我们可以分两种情况讨论:
S=T 时:
这时候由于每一步只能按固定步长跳,所以若第i个位置上有石子并且i mod S=0那么这个石子就一定要被踩到。这是我们只需要统计石子的位置中哪些是S的倍数即可。复杂度O(M)
S<T 时:
首先我们作如下处理:若存在某两个相邻石子之间的空白区域长度>MaxK+2T,我们就将这段区域缩短成长度为 MaxK+2T。可以证明处理之后的最优值和原先的最优值相同。
所以原来的最优解必然在处理之后的最优解解集中。
经过这样的压缩处理,独木桥的长度 L 最多为 (M+1)(MaxK+2T)+M,大约 12000 左右。
压缩之后再用先前的动态规划求解,复杂度就简化成了 O(L(TS)),已经可以在时限内出解了。
这样本题就得到了解决。


Code

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define MAXN 100#define Min(x,y) ((x)<(y)?(x):(y))using namespace std;int l,s,t,m,tot,size;int Minx;int nxt[10000010][3],dis[110];int f[20000010],cnt=1;int main(){    freopen("river.in","r",stdin);    Minx=0x3f3f3f3f;    memset(f,0x3f,sizeof f);    scanf("%d%d%d%d",&l,&s,&t,&m);    for(int i=1;i<=m;i++)scanf("%d",&dis[i]);    sort(dis+1,dis+m+1);    f[0]=0;    if(s==t){        for(int i=1;i<=m;i++)            if(dis[i]%s==0)tot++;        printf("%d\n",tot);    }    else{        dis[m+1]=l;        for(int i=2;i<=m+1;i++)            if(dis[i]-dis[i-1]+1>MAXN+2*t){                nxt[++nxt[0][0]][0]=dis[i-1];                nxt[nxt[0][0]][1]=dis[i]-MAXN-2*t;            }        tot=size=1;cnt=0;        int ss,start=1;        f[0]=0;        if(dis[1]>MAXN+2*t){start=dis[1]-MAXN-2*t-1;f[0]=0;}        for(int i=start;i<=l+t-1;(i==nxt[size][0])?(i=nxt[size][1],size++):(i++)){            ++cnt;            if(i==l)ss=cnt;            if(dis[tot]==i&&tot<=m){                for(int j=s;j<=Min(cnt,t);j++)                    f[cnt]=Min(f[cnt],f[cnt-j]+1);                tot++;            }            else                for(int j=s;j<=Min(cnt,t);j++)                    f[cnt]=Min(f[cnt],f[cnt-j]);        }        for(int i=ss;i<=cnt;i++)            Minx=Min(Minx,f[i]);        printf("%d\n",Minx); }    return 0;}
0 0
原创粉丝点击