2020牛客NOIP賽前訓練營-普及組第一場牛牛的跳跳棋題解

雨後qingtian發表於2020-10-25

連結:https://ac.nowcoder.com/acm/contest/7604/B
來源:牛客網

題目描述

牛牛最近在玩一種叫做跳跳棋的遊戲,棋盤可以看成是一個一維的線性陣列,編號從1到n+1。

一開始牛牛的棋子位於第1個格子,遊戲的最終目的是將棋子移動到第n+1個格子。

棋盤1~n的每個格子都有一個“彈力系數”的權值pi。

當棋子位於第i個格子時,它的下一步可以移動到[i−pi,i+pi]範圍內的任意一個格子。

舉例來說,假設第3個格子的彈力系數為2,那麼牛牛下一步可以移動到第1,2,3,4,5格中的任意一格。

現在給定1~n每格的彈力系數pi。

 

牛牛發現,好像有時由於棋盤的pi設定不合理,導致遊戲無法通關。

所以牛牛準備施展他神奇的魔法,他每次施展魔法都可以使得一個格子的彈力系數pip_ipi+1,他可以施展若干次魔法操作不同的格子,但是要求他不能夠重複對一個格子施展魔法。

牛牛想要知道,為了使跳跳棋通關,他最少施展多少次魔法,並且他應該操作哪些格子。

請輸出牛牛的最小操作次數,以及施展魔法的操作序列,操作序列的第i個數表示該次施展魔法的格子編號,由於答案不唯一,所以請你輸出一個最小字典序的答案。

 

最小字典序指:在保證第1個數字儘可能小的前提下,保證第2個數字儘可能的小,然後在此前提下保證第3個數字儘可能的小....以此類推。

輸入描述:

1

2

3

4

5

6

7

第一行輸入一個正整數n表示跳跳棋的格子數目。

 

 

 

接下來輸入一行n個非負整數pi表示跳跳棋前n個格子的彈力系數。

輸出描述:

1

2

3

4

5

6

7

首先輸出一個非負整數ans,表示少施展魔法的次數。

 

 

 

如果ans不為0,則再輸出一行ans個整數表示需要施展魔法的格子編號,請給出一個最小字典序的答案。

示例1

輸入

1

2

12

5 4 3 3 2 1 0 0 0 1 0 0

輸出

1

2

5

4 8 9 10 12

思路

本來以為是dp,考慮到棋子往回走到某個點可以跳得更遠,後來想了一下,棋子可以在【i-pi,i+pi】範圍內任意移動,說明如果後面有可以跳得更遠得地方,我可以一開始就直接跳到更遠得地方,根本沒必要回退。

直接用s表示不用魔法所能到達得最遠距離,當i>s時說明遊戲無法通關,被迫使用魔法。

AC程式碼

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

#include<bits/stdc++.h>

using namespace std;

int a[100005];

int main()

{

    int cn=0,s=1,b=1,x,n;//s表示不用魔法能到達的最遠距離

    scanf("%d",&n);     //b記錄能到達最遠距離的最小下標

    for(int i=1;i<=n;++i)//保證字典序最小

    {

        scanf("%d",&x);

        if(i>s)

          a[cn++]=b;//沒辦法,被迫使用魔法

        if(i+x>s)

          s=i+x,b=i;//最遠距離更新,順便記錄最小下標

    }

    if(s!=n+1)

      a[cn++]=b;

    printf("%d\n",cn);

    for(int i=0;i<cn;++i)

      printf("%d%c",a[i],i==cn-1?'\n':' ');

    return 0;

}

相關文章