• 刷题记录:牛客NC16655[NOIP2005]过河


    传送门:牛客

    题目描述:

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

    首先,这道题的dp并不难推,随便推一推就可以出来了.显然我们每一个点都是可以被前面的点通过跳跃转移而来的,也就是:

    d p [ i ] = m a x ( d p [ i − j ] + i f   h a s   s t o n e ) dp[i]=max(dp[i-j]+if\ has\ stone) dp[i]=max(dp[ij]+if has stone) j ∈ [ s , t ] j\in[s,t] j[s,t]

    但是当你仔细观察我们的数据范围时就会发现光光只有上述操作其实还是过不去本题的,因为我们的长度达到了 1 e 9 1e9 1e9,我们不可能开这么大的数组

    所以我们需要进行路劲压缩操作,在这里我们不用数论知识进行证明,我们使用一种更为简单的方式进行证明

    首先我们有这样的一个结论,也就是当我们的两个石头直接的距离差达到 > s ∗ t >s*t >st时我们完全可以使用我们的数字来组成这个范围内的任意一个数字.因为我们会发现我当数据等于 s ∗ t s*t st时我们显然是可以是可以使用t个s来组成,当我们的数字大于s*t但是小于(t+1)*s时,我们可以将我们的前面的t个s逐步的增大,显然我们是可以组成的这里使用一种比较形象的方法浅浅的证明了一下

    对于更加严谨的证明在这里就不给出了,可以自行搜索学习

    嗯,我们还需要特判s==t的时候

    下面是具体的代码部分:

    
    ```#include <iostream>
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    typedef long long ll;
    #define inf 0x3f3f3f3f
    #define root 1,n,1
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    inline ll read() {
    	ll x=0,w=1;char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	return x*w;
    }
    #define maxn 1000000
    #define ll_maxn 0x3f3f3f3f3f3f3f3f
    const double eps=1e-8;
    int l,s,t,m;
    int dp[maxn];int a[maxn];int vis[maxn];
    int shinkpoint[maxn];int b[maxn];
    int main() {
    	l=read();s=read();t=read();m=read();
    	for(int i=1;i<=m;i++) a[i]=read();
    	if(s==t) {
    		int cnt=0;
    		for(int i=1;i<=m;i++) {
    			if(a[i]%s==0) cnt++;
    		} 
    		cout<<cnt<<endl;
    		return 0;
    	}
    	sort(a+1,a+m+1);
    	memset(dp,0x3f,sizeof(dp));
    	dp[0]=0;
    	for(int i=1;i<=m;i++) {
    		if(a[i]-a[i-1]>=90) {
    			b[i]=b[i-1]+90;
    		}else {
    			b[i]=b[i-1]+a[i]-a[i-1];
    		}
    		vis[b[i]]=1;
    	}
    	int r=b[m]+90;
    	for(int i=1;i<=r;i++) {
    		for(int j=s;j<=t;j++) {
    			if(i-j<0) continue;
    			dp[i]=min(dp[i-j]+vis[i],dp[i]);
    		}
    	}
    	int ans=inf;
    	for(int i=b[m];i<=r;i++) ans=min(ans,dp[i]);
    	cout<<ans<<endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    tensor.nozero(), mask, [mask]
    Android 开发常见问题
    windows terminal鼠标右键打开
    Ansible自动化运维之playbooks剧本
    数据结构--双向链表(图文)
    【渝偲】ICG-HSA,吲哚菁绿标记人血清白蛋白;ICG标记各种蛋白
    vue-pdf实现pdf文件预览和分页
    opengl制作天空盒
    独立显卡跟集成显卡有什么差别?
    【无标题】【3D建模制作技巧分享】zbrush中如何卡硬边?
  • 原文地址:https://blog.csdn.net/yingjiayu12/article/details/127769527