1. 程式人生 > >NOIP2017普通組復賽題解四

NOIP2017普通組復賽題解四

str P20 至少 以及 != style int 順序 接下來

四、跳房子

【題目描述】

跳房子,也叫跳飛機,是一種世界性的兒童遊戲,也是中國民間傳統的體育遊戲之一。

跳房子的遊戲規則如下:

在地面上確定一個起點,然後在起點右側畫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≥dg時),他的機器人每次可以選擇向右彈跳的距離為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

【輸入樣例二】

7 4 20
2 6
5 -3
10 3
11 -3
13 1
17 6
20 2

【輸出樣例二】

-1

【輸入輸出樣例1說明】

2個金幣改進後, 小R的機器人依次選擇的向右彈跳的距離分別為2、3、5、3、4、3,先後到達的位置分別為2、5、10、13、17、20,對應1、2、3、5、6、7這6個格子。這些格子中的數字之和15即為小 R 獲得的分數。

【輸入輸出樣例2說明】

由於樣例中7個格子組合的最大可能數字之和只有18,無論如何都無法獲得20分。

【數據規模與約定】

本題共10組測試數據,每組數據10分。

對於全部的數據滿足1≤n≤500000,1≤d≤2000,1≤xi,k≤109,∣si∣<105。

對於第1、2組測試數據,n≤10;

對於第3、4、5組測試數據,n≤500;

對於第6、7、8組測試數據,d=1。

【解析】

#include<bits/stdc++.h>
using namespace std;
struct node{
    int x,v;
}q[500005];
int f[500005];
long long maxx=0;
int n,d,k;
int dis[500005],sc[500005];
bool check (int g)
{
    int low=max (1,d-g),high=d+g;
    int cur=0,head=0,tail=-1;
    memset (f,0,sizeof (f));
    for (int i=1;i<=n;i++)
    {
        for (;cur<i&&dis[cur]<=dis[i]-low;cur++)
        {
            while (head<=tail&&q[tail].v<f[cur])
                tail--;
            if (f[cur]!=-0x3f3f3f3f)
                q[++tail].v=f[cur],q[tail].x=dis[cur];
        }
        while (head<=tail&&dis[i]-q[head].x>high)
            head++;
        f[i]=(head<=tail)?q[head].v+sc[i]:-0x3f3f3f3f;
        if (f[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",&dis[i],&sc[i]);
        maxx+=max (sc[i],0);
    }
    if (maxx<k)
    {
        printf ("-1");
        return 0;
    }
    int l=1,r=dis[n];
    while (l<r)
    {
        int mid=(l+r)/2;
        if (check (mid))
            r=mid;
        else
            l=mid+1;
    }
    printf ("%d",l);
    return 0;
}

以上代碼是AC代碼,用單調隊列,屬於提高組的解法。

NOIP2017普通組復賽題解四