1 条题解

  • 0
    @ 2026-4-29 10:49:42

    首先考虑如果只有代价为 11 的情况怎么求。

    那么我们每跳一次,进入某一个区间,然后再跳一次到另一个区间。

    看看我们会选择跳什么点。

    第一种是直接跳到终点,第二种是跳到下一步能跳的最远的点。

    那么我们既然选择下一步跳最远的点,就可以判断这个最远的点是否达到或者超过终点了。

    我们考虑倍增处理要走几步到达终点,我们需要对最远距离倍增,由于我们选择行动的范围是连续的,且这一步选择的范围一定比上一步的更优,所以我们只需要在起点到目前最远点找一个跳的最远的即可。

    对于寻找跳的最远的点,明显可以使用 ST 表。

    如果你直接维护可能会想到要对每个倍增的值都进行维护,实际上不用,因为你第一步跳的最远,那么你的选择范围就大,那么这个值后面肯定不会被别的值超过。

    那么我们就顺利完成了对于只有为 11 的代价的情况。

    考虑加上 22 的情况,第一种方法就是拆边,把代价为 22 的情况改为先去一个特殊点,然后再由这个特殊点到达这个目标位置。

    还有一种写法就是在维护正常倍增时维护消耗 2k12^k-1 个的情况,这样在倍增进行合并的时候可以通过这个值来维护中间为一次操作的情况。

    然后就可以写代码了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int read(){
    	char c=getchar();int x=0;bool f=0;
    	while(c>'9'||c<'0'){
    		if(c=='-')f=1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	if(f)return -x;
    	return x;
    }
    int n,m,v[500005],w[500005],stv[500005][22],stw[500005][22],st[500005][22][2],lg[500005];
    int cmpv(int x,int y){
    	if(v[x]>v[y])return x;
    	return y;
    }
    int cmpw(int x,int y){
    	if(w[x]>w[y])return x;
    	return y;
    }
    int queryv(int l,int r){
    	int k=lg[r-l+1];
    	return cmpv(stv[l][k],stv[r-(1<<k)+1][k]);
    }
    int queryw(int l,int r){
    	int k=lg[r-l+1];
    	return cmpw(stw[l][k],stw[r-(1<<k)+1][k]);
    }
    
    std::vector<int> solve(std::vector<int> &V, std::vector<int> &W, std::vector<std::pair<int,int>> &queries){
    	n=V.size();
    	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
    	for(int i=0;i<n;i++)v[i]=min(V[i]+i,n-1),stv[i][0]=i;
    	for(int i=0;i<n;i++)w[i]=min(W[i]+i,n-1),stw[i][0]=i;
    	for(int i=1;i<=20;i++)for(int j=0;j+(1<<i)-1<n;j++)stv[j][i]=cmpv(stv[j][i-1],stv[j+(1<<i-1)][i-1]);
    	for(int i=1;i<=20;i++)for(int j=0;j+(1<<i)-1<n;j++)stw[j][i]=cmpw(stw[j][i-1],stw[j+(1<<i-1)][i-1]);
    	for(int i=0;i<n;i++)st[i][0][0]=v[i],st[i][0][1]=i;
    	for(int i=0;i<n;i++)st[i][1][0]=max(w[i],v[queryv(i,v[i])]),st[i][1][1]=v[i];
    	for(int i=2;i<=20;i++)for(int j=0;j<n;j++){
    		st[j][i][0]=max({st[queryv(j,st[j][i-1][0])][i-1][0],st[queryw(j,st[j][i-1][0])][i-1][0],st[queryw(j,w[queryw(j,st[j][i-1][1])])][i-1][1],st[queryv(j,w[queryw(j,st[j][i-1][1])])][i-1][1]});
    		st[j][i][1]=max({st[queryv(j,st[j][i-1][1])][i-1][0],st[queryw(j,st[j][i-1][1])][i-1][0],st[queryv(j,st[j][i-1][0])][i-1][1],st[queryw(j,st[j][i-1][0])][i-1][1]});
    	}
    	vector<int> ans;
    	for(auto tmp:queries){
    		int s=tmp.first,t=tmp.second;
    		int j=s,k=-1,res=0;
    		for(int i=20;i>=1;i--){
    			int j2=max(st[queryv(s,j)][i][0],st[queryw(s,j)][i][0]);
    			if(k!=-1)j2=max({j2,st[queryv(s,w[queryw(s,k)])][i][1],st[queryw(s,w[queryw(s,k)])][i][1]});
    			int k2=max(st[queryv(s,j)][i][1],st[queryw(s,j)][i][1]);
    			if(k!=-1)k2=max({st[queryv(s,k)][i][0],st[queryw(s,k)][i][0],k2});
    			if(j2<t)j=j2,k=k2,res+=(1<<i);
    		}
    		int j2=st[queryv(s,j)][0][0];
    		if(k!=-1)j2=max({j2,w[queryw(s,k)],w[queryw(s,k)]});
    		if(j2<t)res++;
    		res++;
    		ans.push_back(res);
    	}
    	return ans;
    }
    
    • 1

    信息

    ID
    9602
    时间
    5000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者