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