Codeforces Round #751 (Div. 2)-D. Frog Traveler

传送门

题意:

一只青蛙在位置 \(n\),在位置 \(i\) 每次可以向上跳 \(1\) ~ \(a[i]\) 格,每次跳到位置 \(j\) 会下滑 \(b[j]\) 格,问最少的跳跃次数跳到井口。输出方案。

做法:

\(f[i]\) 表示位置 \(i\) 先下滑后跳到顶部(位置 \(0\)) 所需的最小步数,利用线段树记录区间 \(f[i]\) 的最小值与最小值位置,求 \(f[i]\) 取其下滑后位置可以上跳到的位置中最小步数加一即可,不用担心下面会有一些小于 \(i\) 的地方 \(f\) 未更新,因为是从下向上跳,并且可跳的步数为 \(1\) ~ \(a[i]\),因此既然能跳到 \(i\),那必然能跳到 \(i\) 滑下再跳的地方,跳到 \(i\) 滑下去再跳显然不优。

code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e5+8;
    int n;
    struct node{
    	int x,t;
    	node(int xx=1061109568,int tt=-1){x=xx;t=tt;}
    } tr[N<<2];
    int a[N],b[N];
    int ans[N];
    void ch(int k,int l,int r,int x,int v)
    {
    	if(l==r){
    		tr[k].x=v;
    		tr[k].t=l;
    		return;
    	}
    	int mid=l+r>>1;
    	if(x<=mid) ch(k<<1,l,mid,x,v);
    	else ch(k<<1|1,mid+1,r,x,v);
    	tr[k]=tr[k<<1].x<tr[k<<1|1].x?tr[k<<1]:tr[k<<1|1];
    }
    node ask(int k,int l,int r,int x,int y)
    {
    	if(x>y) return node{1061109568,-1};
    	if(x<=l&&r<=y) return tr[k];
    	int mid=l+r>>1;
    	node t1,t2;
    	if(x<=mid) t1=ask(k<<1,l,mid,x,y);
    	if(y>mid) t2=ask(k<<1|1,mid+1,r,x,y);
    	return t1.x<=t2.x?t1:t2;
    }
    int main()
    {
    	memset(tr,0x3f,sizeof(tr));
    	cin>>n;
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    	for(int i=1;i<=n;i++)
    	{	
    		if(a[i+b[i]]>=i+b[i]) ch(1,1,n,i,1);
    		else{
    			node tt=ask(1,1,n,max(1,min(i+b[i],n)-a[min(i+b[i],n)]),min(i+b[i],n));
    			if(tt.x!=-1) ch(1,1,n,i,tt.x+1),ans[i]=tt.t;
    		}
    	}
    	
    	node pp=ask(1,1,n,n,n);
    	if(pp.x>=1061109568) puts("-1");
    	else {
    		printf("%d\n",pp.x);
    		int xx=n;
    		while(xx>0){
    			xx=ans[xx];
    			printf("%d ",xx);
    		}
    	}
    }


posted @ 2021-10-27 19:37  ☄️ezuyz☄️  阅读(72)  评论(0编辑  收藏  举报