zoukankan      html  css  js  c++  java
  • 跳房子

    跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。
    跳房子的游戏规则如下:在地面上确定一个起点,然后在起点右侧画 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分,请问他至少要花多少金币来改造他的机器人
    输入
    第一行三个正整数 n,d,k
    分别表示格子的数目,改进前机器人弹跳的固定距离,以及希望至少获得的分数。
    相邻两个数之间用一个空格隔开。
    接下来 n 行,每行两个正整数xi, si,分别表示起点到第i个格子的距离以及第i个格子的分数。
    两个数之间用一个空格隔开。保证xi按递增顺序输入。
    输出
    共一行,一个整数,表示至少要花多少金币来改造他的机器人。
    若无论如何他都无法获得至少 k 分,输出-1。
    样例输入 
    7 4 10
    2 6
    5 -3
    10 3
    11 -3
    13 1
    17 6
    20 2
    样例输出 
    2
    花费 2 个金币改进后,小 R 的机器人依次选择的向右弹跳的距离分别为 2,3,5,3,4,3,
    先后到达的位置分别为 2,5,10,13,17,20,对应 1, 2, 3, 5, 6, 7 这 6 个格子。
    这些格子中的数字之和 15 即为小 R 获得的分数。
    提示
    1 ≤ n ≤ 500000, 1 ≤ d ≤ 2000, 1 ≤ xi , k ≤ 10^9, |si| < 10^5。

    Sol:二分答案出来,然后暴力Dp

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    long long a[500005],w[500005],f[500005],n,d,k,r,l,ans=-1;
    bool cleck(long long mid)
    {
        memset(f,-127,sizeof(f));
        f[0]=0;
        long long ans=0,minn=d-mid>0?d-mid:1,maxx=d+mid;
        for(int i=1;i<=n;i++)
        {
            for(int j=i-1;j>=0;j--)
            {
                if(a[i]-a[j]>maxx)break;
                if(a[i]-a[j]<minn)continue;
                if(f[i]<=f[j]+w[i])
                    f[i]=f[j]+w[i];
            }
            ans=ans>f[i]?ans:f[i];
            if(ans>=k)
               return true;
        }
        return false;
    }
    int main()
    {
        scanf("%lld%lld%lld",&n,&d,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&a[i],&w[i]);
            r=r>a[i]-a[i-1]?r:a[i]-a[i-1];
        }
        r=r>d?r:d;
        while(l<=r)
        {
            long long mid=(r+l)/2;
            if(cleck(mid))
            {
                r=mid-1;
                ans=mid;
            }
            else
                l=mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

      

    
    
      

    Sol2:二分答案出来,然后单调队列维护,其实就是从一段区间中选出一个最大的值。

    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int maxm=500007;
    int n,d,k;
    struct node
    {
     int x,z;
    }a[maxm];
    int ans=-1;
    ll dp[maxm];
    int q[maxm];
    bool check(int x)
    {
      int maxx,minn;
      if(x<d)
      minn=d-x;
      else minn=1;
      maxx=d+x;
      memset(dp,-0x3f,sizeof(dp));
      dp[0]=0;
      int j=0; //j的初值为0 
      int h=1,t=0;
      for(int i=1;i<=n;i++) //准备跳到哪一个点上去 
      {
        for(;a[j].x+minn<=a[i].x;j++)
        //j代表可以跳到i点的那些点 
        {
          while(h<=t&&dp[q[t]]<=dp[j]) 
    	        t--;
    	  //维护一个单调递减的队列 
    	  q[++t]=j;	
        }
        while(h<=t&&a[q[h]].x+maxx<a[i].x) 
        //某些点离i的距离大于maxx时,则不能从其跳到i点了 
    	      h++;
        if(h<=t) 
    	    dp[i]=dp[q[h]]+a[i].z;
        if(dp[i]>=k) 
    	   return 1;
      }
      return 0;
    }
    int main()
    {
     scanf("%d%d%d",&n,&d,&k);
     for(int i=1;i<=n;i++)
     scanf("%d%d",&a[i].x,&a[i].z);
     int l=0,r=a[n].x;
     while(l<=r)
     {
      int mid=(l+r)>>1;
      if(check(mid))
      {
        ans=mid;
        r=mid-1;
      }
      else
      l=mid+1; 
     }
     printf("%d
    ",ans);
     return 0;
    }
    

      

  • 相关阅读:
    Chrome触发唤起IE, 注册唤起程序
    .net post请求过长 , 超过配置 maxQueryStringLength值
    eclipse 初探踩坑实录
    eslint 报error
    前端3小时配置空白机环境
    sql语句
    maven3.04管理jetty9.2.10启动web项目
    Oracle日期时间
    AngularJS向指令传递数据
    jetty和tomcat启动项目
  • 原文地址:https://www.cnblogs.com/cutemush/p/13634981.html
Copyright © 2011-2022 走看看