• Luogu P1052 过河(dp)


    P1052 过河

    题意

    题目描述

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

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

    输入输出格式

    输入格式:

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

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

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

    输出格式:

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

    输入输出样例

    输入样例#1:

    10
    2 3 5
    2 3 5 6 7
    

    输出样例#1:

    2
    

    说明

    对于(30\%)的数据,(Lleq 10000)

    对于全部的数据,(Lleq 10^9)

    (2005)提高组第二题

    思路

    先考虑部分分的做法。我们定义(dp[i])为跳到坐标(i)时所需踩的最少石头数,那么(dp[i])可以从(dp[i-t],dp[i-t+1],dots ,dp[i-s])转移过来。

    但是当(Lleq 10^9)时,数组显然已经开不下了,就算空间够,时间上也不能完成。

    想象这么一段区间,它以石头开头,以石头结尾,而且它十分的长,我们会发现,这一段区间中的大部分(dp)值相同,因为中间是没有石头踩的。所以我们可以把这么长的一段区间压缩成很少数目的点,然后直接(dp)就好了。

    不过还有一个特例:当(s=t)时,不能用上述方法,我们就特判之后数学方法处理就好了。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=50005,B=100;
    int l,s,t,m,last,ans=INT_MAX,dp[MAXN],a[105],p[MAXN],hjj[MAXN];
    int read()
    {
        int re=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return re;
    }
    int main()
    {
        l=read(),s=read(),t=read(),m=read();
        for(int i=1;i<=m;i++) a[i]=read();
        if(s==t)
        {
            ans=0;
            for(int i=1;i<=m;i++) if(a[i]%s==0) ans++;
            printf("%d",ans);
            return 0;
        }
        a[0]=0,a[m+1]=l,m+=2;
        sort(a,a+m);
        for(int i=1;i<m;i++)
            if(a[i]-a[i-1]<=B) last+=a[i]-a[i-1],hjj[last]=1;
            else last+=B,hjj[last]=1;
        hjj[last]=0;
        memset(dp,0x3f,sizeof dp);
        dp[0]=0;
        for(int i=0;i<=last;i++)
            for(int j=s;j<=t;j++)
                dp[i+j]=min(dp[i+j],dp[i]+hjj[i+j]);
        for(int i=0;i<=t;i++) ans=min(ans,dp[last+i]);
        printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    updatepanel,linkbutton一点问题
    URL编码处理
    习惯
    style.display,有点问题
    [转]Atlas goes M2.2 or June CTP
    贴代码——从泛型数组中递归删除不符合要求的项
    做好项目,思想要不得
    关于MemoryStream类
    DateTimePicker控件的使用
    Console“自服务”读取文件
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9903912.html
Copyright © 2020-2023  润新知