CodeForces1601BFrogTraveler

cf?crossfire!

Frog Traveler CodeForces - 1601B

题意:有一只井底之蛙,井深度为n < 3e5,对于每个深度i,最多可以跳ai步,当从一个位置跳到i后,会滑下去bi步。问最少跳多少步可以跳到地面(即i=0)

·
·
·
·
·
·
··

·
·
·
·
·
·

·
·
·
·
·
·

·
·
·
·
·
·
·
·
··
·
·
思路:dp,令dp[ i ]=跳到i位置所需要的最少步数。假设从i位置开始跳,i位置能跳到的集合为s=[ i,i-a[ i ] ];所以dp[ j ]=min(dp[ i ]+1,dp[ j ]),j属于s。
由于每次更新的区间是一段连续的区间,所以我们可用线段树维护区间最小值。复杂度O(n * logn)。
其实还有O(n)的做法,方法就是,我们不妨从最低点开始跳。那么可以得到一段连续的区间的dp值都为1。对于这一段区间,我们只要找到这段区间能跳到的最高点,那么从最高点到这段区间的dp值都为2,依次类推。就像双指针的操作了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<bits/stdc++.h>
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
#define INF 0x7fffffff
typedef long long ll;
typedef pair<ll,ll> P;
const ll maxn=3e5+11;
ll ar[maxn],br[maxn],c[maxn];
ll n;
vector<ll> path;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(ll i=1;i<=n;i++) cin>>ar[i];
for(ll i=1;i<=n;i++) cin>>br[i];
for(ll i=1;i<=n;i++) c[i]=i+br[i];
ll l=n,h=n-ar[n];
ll ans=0;
while(l>=h && h>0){
ll minn=INF,v;
for(ll i=l;i>=h;i--){
if(c[i]-ar[c[i]]<minn){
minn=c[i]-ar[c[i]];
v=i;
}
}
path.push_back(v);
l=h-1,h=minn;
ans++;
}
if(h>0) cout<<-1<<endl;
else{
cout<<ans+1<<endl;
for(auto i=path.begin();i!=path.end();i++) cout<<*i<<" ";
cout<<0;
}
return 0;
}