zoukankan      html  css  js  c++  java
  • P3957 跳房子(二分答案+单调队列优化DP)

    题目链接:https://www.luogu.org/contestnew/show/4468

    题目大意:跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

    跳房子的游戏规则如下:

    在地面上确定一个起点,然后在起点右侧画 n 个格子,这些格子都在同一条直线上。每个格子内有一个数字( 整数),表示到达这个格子能得到的分数。玩家第一次从起点开始向右跳, 跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳,依此类推。规则规定:

    玩家每次都必须跳到当前位置右侧的一个格子内。玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和。

    现在小 R 研发了一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的缺陷,它每次向右弹跳的距离只能为固定的 d。小 R 希望改进他的机器人,如果他花 g 个金币改进他的机器人,那么他的机器人灵活性就能增加 g, 但是需要注意的是,每次弹跳的距离至少为 1。 具体而言, 当g < d时, 他的机器人每次可以选择向右弹跳的距离为 d-g, d-g+1,d-g+2, …, d+g-2, d+g-1, d+g; 否则( 当g ≥ d时),他的机器人每次可以选择向右弹跳的距离为 1, 2, 3, …, d+g-2, d+g-1, d+g。

    现在小 R 希望获得至少 k 分,请问他至少要花多少金币来改造他的机器人。

    解题思路:显然是一道DP题,然后可以总结为以下几点:

         ①g的枚举范围很大,可以用二分枚举。

         ②dp[i]表示在第i个格子上的最大得分,score[i]表示第i个格子上的分值,dis[i]表示第i个格子离出发点的距离,可得到状态转移方程:dp[i]=max{dp[j]+score[i]}(j<i,max(d-g,1)<=dis[i]-dis[j]<=d+g)

         ③按上述方法,复杂度依旧到达了n^2lg(M_g),可以知道,dp[i]是跟距离成正比的,可以用单调队列优化,最后复杂度为O(nlg(M_g))。

         ④还犯了一个小错误,就是默认起点可以到达第一个格子了,O(≧口≦)O。

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 typedef long long LL;
     7 const int N=5e5+5;
     8 const long long INF=4e18;
     9 
    10 int n,d,k;
    11 LL dis[N],score[N],dp[N],q[N];
    12 
    13 bool judge(int i,int j,int g){
    14     if(dis[i]-dis[j]<=g+d&&dis[i]-dis[j]>=max(d-g,1))
    15         return true;
    16     return false;
    17 }
    18 
    19 bool check(int g){
    20     //错误:默认了0可以到达第一个点 
    21     int head=0,tail=0,cur=0,qmin=max(d-g,1),qmax=d+g;
    22     q[tail++]=0;
    23     for(int i=1;i<=n;i++){
    24         while(head+1<tail&&dis[i]-dis[q[head]]>qmax){
    25             head++;
    26         }
    27         if(judge(i,q[head],g))
    28             dp[i]=dp[q[head]]+score[i];
    29         else
    30             dp[i]=-INF;
    31         if(dp[i]>=k)
    32             return true;
    33         while(cur<=i&&dis[i+1]-dis[cur]>=qmin){
    34             //能到达q[tail-1]的肯定能到达cur点,且dp[cur]价值较大,所以q[tail-1]点可以舍去 
    35             while(head+1<=tail&&dp[q[tail-1]]<=dp[cur]){
    36                 tail--;
    37             }
    38             q[tail++]=cur++;
    39         }
    40     }
    41     return false;
    42 }
    43 
    44 int main(){    
    45     scanf("%d%d%d",&n,&d,&k);
    46     for(int i=1;i<=n;i++){
    47         scanf("%lld%lld",&dis[i],&score[i]);
    48     }
    49     int l=0,r=1e9,cost=-1;
    50     while(l<=r){
    51         int mid=(l+r)/2;
    52         if(check(mid)){
    53             if(cost==-1||cost>mid)
    54                 cost=mid;
    55             r=mid-1;
    56         }
    57         else
    58             l=mid+1;
    59     }
    60     printf("%d
    ",cost);
    61     return 0;
    62 }
  • 相关阅读:
    使用uwsgi --http :80 --wsgi-file test.py 在浏览器上无法访问(头疼了我一天)
    linux部署django启动项目报错误
    linux python3使用最新sqlite3版本
    linux上部署python本地开发环境
    Linux下安装Python3.9.0
    python上传图片到本地
    Python:手机号码验证
    PHP 自带的加密解密函数
    html中或者app中在线预览word文档,PDF,PPT
    Python 列表解析
  • 原文地址:https://www.cnblogs.com/fu3638/p/7840504.html
Copyright © 2011-2022 走看看