zoukankan      html  css  js  c++  java
  • 洛谷 P1052 过河 (压缩路径)

    P1052 过河

    题目描述

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

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

    输入输出格式

    输入格式:

     

    第一行有1个正整数L(1L109),表示独木桥的长度。

    第二行有3个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离及桥上石子的个数,其中1ST10,1M100。

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

     

    输出格式:

     

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

     

    输入输出样例

    输入样例#1: 复制
    10
    2 3 5
    2 3 5 6 7
    
    输出样例#1: 复制
    2

    说明

    对于30%的数据,L10000;

    对于全部的数据,L10^9。

    首先看到这道题目很容易想到跑dp的哇  然而定睛一看这个数据范围.....  1e9...

    再见再见 是在下输了...

    但是想来想去还是只有垃圾dp  然后又看到石头的数量是特别少的 所以很容易出现两个石头之间的路径特别特别长

    所以就考虑压缩路径

    想想怎么压缩呢 又可以看到每一步跳的范围也是很小的 在 $10$ 以内 所以考虑用 $lcm$ 压缩路径 并且使这段路径可以正常跑dp

    怎么用 $lcm$ 压缩呢  如图 对于两块石头 $a,b$ 的一段路径 假定我们的压缩路径每段长度为 $2520$ ($1$ 到 $10$ 的$lcm$)

    上面是压缩之后的 假设这一步距离为 $x$ 那么有他按照这个步伐不变 跳出压缩路径之后仍然落在这个点上

    跳完这段路径要$k$ 步 则需要判断$2520 + x$ 与 $k * x$ 的关系

    因为 $2520$ 是 $x$ 的倍数 所以 $x | 2520 + x$ 也就是说他会跳在同一个点 压缩路径成功

    所以具体实现就是两块石头之间的路径长度模 $2520$ 剩下的长度正常跑 $dp$ 就可以了

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 3 * 1e6 + 5;
    const int mod = 2520;
    int n,L,S,T;
    int dp[N],st[300],f[300];
    bool vis[N];
    int dis[105][105];
    
    int main( ) {
        
        scanf("%d",& L);
        scanf("%d%d%d",& S,& T,& n);
        for(int i = 1;i <= n;i ++) {
            scanf("%d",& st[i]);
        }
        st[n + 1] = L;
        sort(st + 1,st + n + 2);
        int las = 0;
        f[0] = 0;
        memset(dp,0x3f3f3f,sizeof(dp));
        dp[0] = 0;
        for(int i = 1;i <= n + 1;i ++) { 
            f[i] = f[i - 1] + (st[i] - st[i - 1]) % mod;
            if(i != n + 1) vis[f[i]] = true;
        }
        for(int i = 1;i <= f[n + 1] + T;i ++) {
            for(int j = S;j <= T;j ++) {
                if(i - j < 0) break;
                if(vis[i]) dp[i] = min(dp[i],dp[i - j] + 1);
                else dp[i] = min(dp[i],dp[i - j]);
            }
        }
        int ans = 10000000;
        for(int i = f[n + 1];i <= f[n + 1] + T;i ++) 
            ans = min(ans,dp[i]);
        printf("%d",ans);
    }
  • 相关阅读:
    合同主体列表添加两条合同主体,返回合并支付页面,支付总弹"请选择合同主体",删除后,竟然还能支付(改合并支付页面的字段状态)
    (TODO:)下载图片,报错:warning: could not load any Objective-C class information from the dyld shared cache. This will significantly reduce the quality of type information available.
    GCD死锁 多线程
    iOS知识总结
    快速排序,冒泡排序,选择排序
    fight
    3D Touch
    Xcode 调试技巧
    右滑退出手势及隐藏导航栏存在的风险
    C语言-第5课
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9573923.html
Copyright © 2011-2022 走看看