CF1601B Frog Traveler 题解


题意

你是一只青蛙(雾),现在你掉到了一个\(n\)米深的井里,当你位于深度为\(i\)的位置时,你可以往上跳\((0,a_i]\)米中的任意一个整数距离,如果你没有跳出去,那么你需要休息,假设你在深度为\(j\)的位置处休息,你就会往下掉\(b_j\)米,现在请问,最少多少步能跳出去,并且输出跳出去的方案。

做法

发现需要输出方案,考虑用\(bfs\)来做,我们发现如果我们跳到了一个位置\(j\),那么深度小于\(j\)的位置我们一定都已经在之前的跳跃过程中枚举过,也就是已经入队了,所以没有再次遍历一遍的需要。所以我们可以维护一个现在已经枚举到的最高位置,然后每次取出队首去扩展位置的时候,我们只需要枚举从之前的最高位置到这个点能到的最高位置即可,这样可以保证每个元素最多被入队一次,保证了时间复杂度为\(O(n)\)。然后对于输出方案,用一种类似链表的方法输出即可。

代码


#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int qu[N*3],hea=1,tal=0;
int a[N],b[N],ans[N],pre[N],sp[N];
bool used[N];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int j=1;j<=n;j++)
		scanf("%d",&b[j]);
	used[n]=1;
	qu[++tal]=n;
	int mins=n;
	bool flag=0;
	while(hea<=tal){
		int j=qu[hea++];
		if(j-a[j]<=0){
			flag =1;
			printf("%d\n",ans[j]+1);
			vector<int> otp;
			int now=j;
			while(now!=n){
				otp.push_back(pre[now]);
				now=sp[now];
			}
			for(int i=otp.size()-1;i>=0;i--)
				printf("%d ",otp[i]);
			printf("%d\n",0);
			break;
		}
		for(int i=mins-1;i>=j-a[j];i--){
			if(used[i])
				continue;
			int dest=i+b[i];
			if(used[dest])
				continue;
			sp[dest]=j;//sp+pre = where
			used[dest]=1;
			pre[dest]=i;// before dropped 
			ans[dest]=ans[j]+1;
			qu[++tal]=dest;
		}
		mins=min(mins,j-a[j]);
	}
	if(!flag)
		puts("-1");
	return 0;
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM