1 条题解

  • 0
    @ 2026-5-2 21:36:22

    题目大意

    nn 颗行星,求从 11 出发到 nn 所需最少加注次数,无解输出 00

    思路

    考虑贪心,发现每次选可以走到最远的 ii 加注最优。 :::info[证明] 因为可以在中途停下,所以每次选走到最远的包含了所有情况。假设在一次飞行中,没选最优情况,而选了 jj,其中 aj<aia_j<a_i,则本来当前最大到达区间 [1,ai][1,a_i],而现在只有 [1,aj][1,a_j],若下次加注的位置在 (aj,ai](a_j,a_i],那么在 jj 加注没法保证最优。 ::: 预处理 v[i]v[i] 表示 ii 之后第一个与 ii 同类型的位置。

    初始区间 [l=1,r=vi][l=1,r=v_i]11 已加注。

    每次在 (l,r](l, r] 中找 viv_i 的最大值,设 kk 表示 viv_i 最大的 ii

    若最大值 r\le r 则无解。

    否则加注 kk,更新 r=v[k]r=v[k],继续。

    r=nr=n 时结束。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,a[300005],u[300005],v[300005],l=1,r,k=1,s=1,d;
    vector<ll> t;
    int main(){
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    		v[u[a[i]]]=i;
    		u[a[i]]=i;//u表示上一个a[i]的下标
    	}
    	r=v[1];//初始区间右端点
    	t.push_back(1);//记录加注路径
    	while(1){
    		if(r==n){//达到n
    			printf("%lld\n",s);
    			for(int i=0;i<t.size();i++)printf("%lld ",t[i]);
    			break;
    		}
    		d=0;//记录a[i]最大值
    		while(l<r){
    			l++;//l不会退,一路扫到r
    			if(v[l]>d){
    				d=v[l];
    				k=l;//k记录最大i
    			}
    		}
    		if(d<=r){//无解
    			printf("0");
    			break;
    		}
    		t.push_back(k);//最优选择k放入加注路径
    		s++;
    		r=d;
    	}
    	return 0;
    }
    • 1

    信息

    ID
    10347
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者