luogu p1052 过河

题目描述

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

题目给出独木桥的长度\(L\) ,青蛙跳跃的距离范围\(S,T\) ,桥上石子的位置 . 你的任务是确定青蛙要想过河 ,最少需要踩到的石子数 .

输入格式

第一行有\(1\)个正整数\(L(1 \le L \le 10^9)\) ,表示独木桥的长度 .

第二行有\(3\)个正整数\(S\) , \(T\) , \(M\) ,分别表示青蛙一次跳跃的最小距离 ,最大距离及桥上石子的个数 ,其中\(1 \le S \le T \le 10\) , \(1 \le M \le 100\) .

第三行有\(M\)个不同的正整数分别表示这\(M\)个石子在数轴上的位置 (数据保证桥的起点和终点处没有石子) . 所有相邻的整数之间用一个空格隔开 .

输出格式

一个整数 ,表示青蛙过河最少需要踩到的石子数 .

题解:

很容易就想出一个丑陋\(dp\)转移方程 , \(dp[i]=min_{s\leq j\leq t}(dp[i-j]+stone[i])\) , \(stone[i]\)为该点有无石头 . 可是\(L\)的范围是\(1e9\) . 想想应该如何优化 .

自己手玩一下发现 , 只要\(L\)够长 , 在距离为\(s,t\)的最小公倍数之后的每个点都能被青蛙跳到 (别问我为什么我也不会证 , 画一下图就很显然了 . 那么考虑只要两个石头之间的距离大于\(lcm_{s,t}\) , 那么在\(lcm_{s,t}\)之后的所有点都能被跳到 , 那么我们把这两个点之间的距离缩成\(lcm_{s,t}\)就好 (因为反正能跳到 , 在\(lcm_{s,t}\)也是跳在更远也是跳) .

\(code:\)

#include 
using namespace std;
const int M=100+5;
int l,s,t,m,dis;
int st[M],dp[M*M],cx[M*M];
int main(){
    scanf("%d",&l);
    scanf("%d%d%d",&s,&t,&m);
    if(s==t){
        for(int i=1;i<=m;i++){
            scanf("%d",&st[i]);
            if(st[i]%s==0) ++dis;
        }
        printf("%d",dis);
        return 0;
    }
    int lcm=s*t/__gcd(s,t);
    for(int i=1;i<=m;i++) scanf("%d",&st[i]);
    sort(st+1,st+1+m);
    for(int i=1;i<=m;i++){
        st[i]-st[i-1]>lcm ? dis+=lcm : dis+=st[i]-st[i-1];
        cx[dis]=1;
    }
    memset(dp,0x3f,sizeof(dp));
    dp[0]=0;l=lcm+dis;
    for(int i=1;i<=l;i++)
        for(int j=s;j<=t;j++)
            if(i-j>=0) dp[i]=min(dp[i],dp[i-j]+cx[i]);
    int ans=2e9;
    for(int i=dis;i<=l;i++) ans=min(ans,dp[i]);
    printf("%d",ans);
    return 0;
}

转载于:https://www.cnblogs.com/cnyali-xwx/p/11446020.html

你可能感兴趣的:(luogu p1052 过河)