专栏文章

题解:CF207B3 Military Trainings

CF207B3题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miozshrf
此快照首次捕获于
2025/12/03 03:49
3 个月前
此快照最后确认于
2025/12/03 03:49
3 个月前
查看原文

题目传送门

题目大意

每个坦克有一个接收半径 rir_i,每次要从最前面的坦克把信号传给最后一个,最后一个在跑到前面来,重复执行,每两个坦克之间传输信号所需时间为 11,求总的最小时间。

思路

考虑 n300n\le 300 的情况,我们可以使用模拟的方法。首先破环成链,把原序列复制一份接到序列后面,从 2×n2\times n 的位置开始枚举,枚举到 nn,每次都模拟往前跳,找到能接收的范围内的接收半径最大的坦克,跳到他这里,直到跳到发送信号的坦克的位置。
时间复杂度 O(n3)O(n^3)
考虑 n10000n\le 10000 的情况,在先前的暴力的基础上,我们可以用线段树或者 st 表预处理出,每一个坦克 ii[iri,i1][i-r_i,i-1] 范围中能找到最大接收半径的坦克编号,然后每次跳的时候,直接跳到这个范围内的最大接收半径的坦克即可。
这样的话就可以做到在模拟的时候做到 O(n)O(n)。最终时间复杂度为 O(n2)O(n^2)
考虑 n250000n\le 250000 的情况,注意到跳跃可以用倍增处理,fi,jf_{i,j} 表示第 ii 个坦克跳 2j2^j 次能跳到的坦克编号,那么每次都可以跳 2j2^j 次,大大缩减了跳跃的时间,做到 O(logn)O(\log n) 的时间来模拟跳跃。
注意,每次要跳到正好差一次跳到到发送信号的坦克的位置,而且最后到达的位置 ii 不是能跳一步就跳到目标位置的,因为是 ii 的下一次跳跃的位置上的坦克的接收半径包含了目标位置,所以要跳两次。

代码

CPP
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=501010;
ll n,a[N],ans,t[N],fa[N][30],st[N][30];
void init(){
    for(ll i=1;i<=2*n;i++)st[i][0]=i;
    for(ll j=1;j<=29;j++){
        for(ll i=1;i<=2*n-(1<<j)+1;i++){
        	if(a[st[i][j-1]]<a[st[i+(1<<(j-1))][j-1]])st[i][j]=st[i][j-1];
        	else st[i][j]=st[i+(1<<(j-1))][j-1];
            
        }
    }
}
ll query(ll l,ll r){
    ll k=log2(r-l+1);
    if(a[st[l][k]]<a[st[r-(1<<k)+1][k]])return st[l][k];
    else return st[r-(1<<k)+1][k];
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++)a[i]=max(i-a[i],1ll);
    init();
    for(int i=1;i<=2*n;i++){
        fa[i][0]=query(a[i],i);
    }
    for(int j=1;j<=29;j++){
        for(int i=1;i<=2*n;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
    for(int i=1;i<=n;i++){
        ll cnt=2;
        ll now=i+n-1;
        if(a[now]<=i){
            ans++;
            continue;
        }
        for(ll j=29;j>=0;j--){
            if(a[fa[now][j]]>i)cnt+=(1<<j),now=fa[now][j];
        }   
        ans+=cnt;
    }
    cout<<ans;
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...