题目描述
牛牛最近在玩一种叫做跳跳棋的游戏,棋盘可以看成是一个一维的线性数组,编号从1到
n
+
1
n+1
n+1。
一开始牛牛的棋子位于第1个格子,游戏的最终目的是将棋子移动到第
n
+
1
n+1
n+1个格子。
棋盘1~n的每个格子都有一个“弹力系数”的权值
p
i
p_i
pi 。
当棋子位于第i个格子时,它的下一步可以移动到
[
i
−
p
i
,
i
+
p
i
]
[i-p_i,i+p_i]
[i−pi,i+pi]范围内的任意一个格子。
举例来说,假设第3个格子的弹力系数为2,那么牛牛下一步可以移动到第1,2,3,4,5格中的任意一格。
现在给定
1
n
1~n
1 n每格的弹力系数
p
i
p_i
pi。牛牛发现,好像有时由于棋盘的
p
i
p_i
pi设置不合理,导致游戏无法通关。
所以牛牛准备施展他神奇的魔法,他每次施展魔法都可以使得一个格子的弹力系数
p
i
+
1
p_i+1
pi+1,他可以施展若干次魔法操作不同的格子,但是要求他不能够重复对一个格子施展魔法。
牛牛想要知道,为了使跳跳棋通关,他最少施展多少次魔法,并且他应该操作哪些格子。
请输出牛牛的最小操作次数,以及施展魔法的操作序列,操作序列的第i个数表示该次施展魔法的格子编号,由于答案不唯一,所以请你输出一个最小字典序的答案。
最小字典序指:在保证第1个数字尽可能小的前提下,保证第2个数字尽可能的小,然后在此前提下保证第3个数字尽可能的小…以此类推。
输入描述:
第一行输入一个正整数n表示跳跳棋的格子数目。
接下来输入一行n个非负整数
p
i
p_i
pi
表示跳跳棋前n个格子的弹力系数。
输出描述:
首先输出一个非负整数ans,表示少施展魔法的次数。
如果ans不为0,则再输出一行ans个整数表示需要施展魔法的格子编号,请给出一个最小字典序的答案。
示例1
输入
12
5 4 3 3 2 1 0 0 0 1 0 0
输出
5
4 8 9 10 12
说明
除了
"
4891012
"
"4 8 9 10 12"
"4891012"这个操作的答案序列以外,
"
5891012
"
,
"
6891012
"
"5 8 9 10 12","6 8 9 10 12"
"5891012","6891012"也同样是最小操作数下的答案。
但是
"
4891012
"
"4 8 9 10 12"
"4891012"这个答案是字典序最小的,故输出
"
4891012
"
"4 8 9 10 12"
"4891012"。
示例2
输入
8
0 1 0 1 0 1 0 1
输出
4
1 2 4 6
示例3
输入
5
0 0 0 0 0
输出
5
1 2 3 4 5
说明
本样例可以说明,不存在无解的情况,因为你至少可以令所有
p
i
p_i
pi 全都+1。
示例4
输入
5
1 1 1 1 1
输出
0
备注:
对于
20
20
20%的测试数据,保证
1
≤
n
≤
10
1≤n≤10
1≤n≤10
对于
40
40
40%的测试数据,保证
10
≤
p
i
≤
1
10≤p_i ≤1
10≤pi≤1
对于
100
100
100%的测试数据,保证
1
≤
n
≤
1
0
5
,
0
≤
p
i
≤
100
1≤n≤10^5 ,0≤p_i≤100
1≤n≤105,0≤pi≤100
解题思路
这道题是一道贪心。
我们可以看出,往后走是没有任何的必要的。
因为你走是可以走到
[
i
−
p
i
,
i
+
p
i
]
[i-p_i,i+p_i]
[i−pi,i+pi]中的任意一个点,那你走回去,再走回来,其实不如你直接往前走。
那这道题就可以很愉快的用贪心解决了,在用魔法之前竟可能的走到更前面,然后在跳最后一次的地方用一次魔法。
这时候可能会有人问:为什么这样一定可以呢?
因为它无论在什么地方使用魔法,都只能在原来的基础上多走一步,那肯定就是先找到能走到最远地方的最后一点,然后再那个地方用魔法。
然后我们只要在走的时候记录一下在那些地方用了魔法,在到终点之后输出出来就可以了。
题目要求要字典序最小,那我们不往后走,而且如果有两个地方都可以跳到最远点,就选前面的那个。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
int n,a[110000],num[110000],maxn,maxx;
void output(){
printf("%d\n",num[0]);
for(int i=1;i<=num[0];i++)
printf("%d ",num[i]);
}
int main(){
scanf("%d",&n);
maxn=1,maxx=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i])
{
if(a[i]+i>maxn)
{
maxn=a[i]+i;
maxx=i;
if(maxn>n)
{
output();
return 0;
}
}
}
else if(i==maxn)
{
num[++num[0]]=maxx;
maxn++;
maxx=maxn;
if(maxn>n)
output();
}
}
return 0;
}