2020牛客NOIP賽前集訓營-普及組(第一場) 牛牛的跳跳棋

白都_落陽發表於2020-10-21

牛牛的跳跳棋
連結: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設定不合理,導致遊戲無法通關。
所以牛牛準備施展他神奇的魔法,他每次施展魔法都可以使得一個格子的彈力系數pi+1,他可以施展若干次魔法操作不同的格子,但是要求他不能夠重複對一個格子施展魔法。
牛牛想要知道,為了使跳跳棋通關,他最少施展多少次魔法,並且他應該操作哪些格子。
請輸出牛牛的最小操作次數,以及施展魔法的操作序列,操作序列的第i個數表示該次施展魔法的格子編號,由於答案不唯一,所以請你輸出一個最小字典序的答案。

最小字典序指:在保證第1個數字儘可能小的前提下,保證第2個數字儘可能的小,然後在此前提下保證第3個數字儘可能的小…以此類推。
輸入
12
5 4 3 3 2 1 0 0 0 1 0 0
輸出
5
4 8 9 10 12
受同學邀請做題,開始沒做出來,受到點播後,知道是使用貪心來做題,在兩天陸陸續續的思考後,總算做出來了。
對於這道題,我們先看到移動的範圍是[i-pi,i+pi],但是仔細思考之後,就可以發現這個i-pi是沒有必要去使用的,也就是說一條路走到黑,能往前走就往前走,這裡就是貪心策略。然後接著思考,如果對於兩點i1、i2,假設i1+pi1==i2+pi2,那麼我們對於i1和i2施法之後結果是一樣的,兩者都是向前走了一個格子,所以我們只要選擇,兩者之中比較小的一者來進行施法就可以了。我們用last變數表示能夠到達最大距離同時序號最小的節點序號。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
#include<stack>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
int a[100005];
int ans[100005];
int maxx=0,num=0;
int last=1;
int main(){
	#ifdef LOCAL
	freopen(".\\a.in", "r", stdin);
	#endif
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(maxx>=n+1)break;
		if(a[i]+i>maxx){//大於最大值,不需要等於,以此來保證字典序最小
			maxx=a[i]+i;
			last=i;
		}
		if(i==maxx){//說明這裡已經不能走了,必須要進行施法
			num++;
			ans[num]=last;//對last進行施法
			last=i+1;//因為施法後最大距離為i+1,就不需要在i這裡施法了
			maxx++;
		}
	}
	printf("%d\n",num);
	for(int i=1;i<=num;i++){
		printf("%d ",ans[i]);
	}
	return 0;
}

相關文章