欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

跳房子

程序员文章站 2022-06-30 08:43:05
跳房子 题目 【题目描述】 跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。跳房子的游戏规则如下: 在地面上确定一个起点,然后在起点右侧画n个格子,这些格子都在同一条直线上。每个格子内有一个数字(整数),表示到达这个 格子能得到的分数。玩家第一次从起点开始向右跳,跳到起点 ......

跳房子

题目

【题目描述】

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

在地面上确定一个起点,然后在起点右侧画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;
}