跳房子

白昼怎懂夜的黑 提交于 2019-11-28 14:46:37

跳房子

题目

【题目描述】

跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。跳房子的游戏规则如下:

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

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

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

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

【输入格式】

第一行三个正整数 ndk,分别表示格子的数目,改进前机器人弹跳的固定距离,以及希望至少获得的分数。相邻两个数 之间用一个空格隔开。

接下来 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 获得的分数。

【数据规模】

本题共 10 组测试数据,每组数据 10 分。

对于全部的数据满足1n500000,1d2000,1xi,k109,si<105。

对于第1,2组测试数据, n10;

对于第3,4,5 组测试数据, n500

对于第6,7,8 组测试数据, d=1

解析

这题本蒟蒻用了些玄学优化,不用二分,不用单调队列,O(n2)的dp居然过了。

好,说说思路:

首先既然是dp,那么肯定少不了状态:

令f[i]表示到达i格子的最大分数,初值为极小值,

状态转移方程:f[j]=f[i]+s[j],具体的i与j后面会说。

我们在读入的时候,先累加所有分数大于0的,如果maxn(maxn表示累加分数后的结果)小于k,那么直接输出-1,maxn记得开long long不然后5个点全部都会输出-1(说多了都是泪)!

反之我们从0开始累加g的值,即while循环。

每次我们从0到n-1枚举i,如果bj[i]为真(bj[i]表示能否到达i这个格子,初始全为false,由于g是累加的,所以如果之前的g可以到达i,那么之后的g必然也可以到达i,所以只需要初始化bj一次就可以了),

便从i+1到n枚举j,如果x[j]-x[i]<=d+g(x如题目所述),即从i到j的距离小于等于能够跳的最远距离,就判断如果x[j]-x[i]>=max(1,d-g),即从i到j的距离大于等于能过跳的最短距离,

就令bj[j]=true,f[j]=max(f[j],f[i]+s[j]),如果f[j]>=k,那么直接输出当前的g;

如果x[j]-x[i]>d+g,即从i到j的距离大于能够跳的最远距离,那么直接退出j循环,因为x是递增的,那么如果当前点跳不到,后面的点肯定也是跳不到的。

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
int read()
{
    int num=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        num=(num<<1)+(num<<3)+ch-'0';
        ch=getchar();
    }
    return num*w;
}
int n,d,k,g,x[500100],s[500100],f[500100];
long long maxn;
bool bj[500100];
int main()
{
    memset(bj,false,sizeof(bj));
    memset(f,0xcfcfcfcf,sizeof(f));
    bj[0]=true,f[0]=0;
    n=read(),d=read(),k=read();
    for(int i=1;i<=n;i++)
    {
        x[i]=read(),s[i]=read();
        if(s[i]>0) maxn+=s[i];
    }
    if(maxn<k)
    {
        cout<<"-1";
        return 0;
    }
    while(1)
    {
        for(int i=0;i<n;i++)
            if(bj[i])
                for(int j=i+1;j<=n;j++)
                {
                    if(x[j]-x[i]<=d+g)
                    {
                        if(x[j]-x[i]>=max(1,d-g))
                        {
                            bj[j]=true;
                            f[j]=max(f[j],f[i]+s[j]);
                            if(f[j]>=k)
                            {
                                cout<<g;
                                return 0;
                            }
                        }
                    }
                    else break;
                }
        g++;
    }
    return 0;
}
View Code
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!