题意:
输入代表
米深的井。接着一行输入n个数
代表在深度为
的位置能往上跳
到
个单位,再输入n个数
代表在
位置会往下滑
个单位。每次上跳都会紧随一次下滑(跳出井除外),问至少要多少次上跳才能跳出井。输出步数和每次跳完到达的位置。
思路:
上网看别人bfs的题解看得头大,所以决定自己写一篇。
蒟蒻上路请多包涵QwQ
第一眼看到这题想到了dp,于是试着列了个递推式。定义为到达深度为
的位置的最少步数。
想着如何优化的时候发现了一个思路:就一个位置来说,能到达的位置的最小值是能唯一确定的。那就好办了,假设从j能到达的最高点为
,到达j的最少步数为
,那么对于某个位置i来说,我们肯定去找满足
小于i且
最小的点去更新。这可以用类似二维偏序的思路解决:树状数组维护
,每更新到一个位置i,先查询0到i的区间最小值来更新当前的
,再用
更新树状数组以
为下标的最小值。
码完之后仔细一看样例,要输出路径,但上面的思路显然不能维护路径。真是绝绝子,所以恭喜你看了我写的那么多废话。
虽然树状数组不行,但是同样的思路我们可以用优先队列实现。树状数组找最小的的思路可以用优先队列的排序实现,更新的话就用优先队列自带的
和
。详细思路可以结合代码思考。因为要维护路径,所以维护一个
记录前继,最后递归输出就行。复杂度
,应该不是最快的办法,但是很好理解,也能过题,耗时171 ms。
代码:
#include<bits/stdc++.h>
using namespace std;
const int M = 3e5+10;
#define IO ios::sync_with_stdio(false);cin.tie(0)
#define INF 0x3f3f3f3f
#define ll long long
int n;
int a[M],b[M],pre[M];
struct node{
int to,from,step;
bool operator<(const node& b)const{
return step>b.step;
}
};
void print(int x){
if(x==n)return;
print(pre[x]);
cout<<x<<" ";
}
int main(){
#ifdef DEBUG
freopen("in.txt","r",stdin);
#else
IO;
#endif
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i)cin>>b[i];
priority_queue<node> pq;
pq.push({n-a[n],n,0});
int ans=INF;
for(int i=n-1;i>=0;--i){
while(!pq.empty()&&pq.top().to>i)pq.pop();
if(pq.empty())break;
pre[i]=pq.top().from;
if(!i)ans=pq.top().step+1;
pq.push({i+b[i]-a[i+b[i]],i,pq.top().step+1});
}
if(ans==INF)cout<<-1<<endl;
else{
cout<<ans<<endl;
print(0);
cout<<endl;
}
return 0;
}