zoukankan      html  css  js  c++  java
  • CF1032G Chattering

    Solution

    能够显然的想到每个人传递必然是连续的,也就是对于一个 (i) ,他能够到达的区间为 ([i-a_i,i+a_i])

    下一次,就会转移到 ([l,r]) 中能往左和往右的最远端点,所以我们需要记录最值,那么不难想到用ST表去处理区间最值。

    (l_{i,j}) 表示从 (j) 开始 (2^i) 秒能达到的最左端, (r_{i,j}) 同理。然后转移就是 (l_{i,j}=minlimits_{l_{i-1,j}leq tleq r_{i-1,j}}{l_{i-1,t}}\r_{i,j}=maxlimits_{l_{i-1,j}leq tleq r_{i-1,j}}{r_{i-1,t}})

    最后倍增求解即可。

    大细节:因为是在一个环上,并且同时在两个方向走,所以要将环拆开,并复制成三份,然后再进行ST表等操作。

    小细节:当区间覆盖超过 (n) 时,是完全覆盖,肯定有比选此时更优的解,跳过此时即可。

    时间复杂度: (O(nlog n)) (好像比CF官方说的好一点?)

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    const int N=3e5+10;
    int n,a[N],b[N],c[N];
    int Log[N];
    int l[19][N],r[19][N];
    
    struct rmq{
        int st[N][19],val[N];
        int type;
        inline int Max(int x,int y){
            return (val[x]<val[y])?y:x;
        }
        void build(int *b,int n,int _type){
            type=_type;
            for(int i=1;i<=n;i++) st[i][0]=i,val[i]=type*b[i];
            for(int j=1;j<=Log[n];j++){
                for(int i=1;i+(1<<j)-1<=n;i++)
                    st[i][j]=Max(st[i][j-1],st[i+(1<<j-1)][j-1]);
            }
        }
        inline int query(int l,int r){
            int k=Log[r-l+1];
            return Max(st[l][k],st[r-(1<<k)+1][k]);
        }
    }rmq_l,rmq_r;
    
    int main(){
        scanf("%d",&n);
        for(int i=2;i<=3*n;i++) Log[i]=Log[i>>1]+1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i+n]=a[i+n*2]=a[i];
        }
        if(n==1) return puts("0"),0;
        for(int i=1;i<=3*n;i++){
            b[i]=max(1,i-a[i]);
            c[i]=min(3*n,i+a[i]);
        }
        for(int i=0;i<=Log[3*n];i++) r[i][3*n]=3*n,l[i][1]=1;
        for(int i=1;i<=3*n;i++){
            l[0][i]=b[i];
            r[0][i]=c[i];
        }
        rmq_l.build(l[0],n*3,-1);rmq_r.build(r[0],n*3,1);
        for(int i=1;i<=Log[3*n];i++)
            for(int j=1;j<=3*n;j++){
                int posl=rmq_l.query(l[i-1][j],r[i-1][j]);  
                int posr=rmq_r.query(l[i-1][j],r[i-1][j]);
                l[i][j]=min(l[i-1][posl],l[i-1][posr]);
                r[i][j]=max(r[i-1][posl],r[i-1][posr]);
            }
        for(int j=n+1;j<=n*2;j++){
            int u=j,v=j;
            int ans=0;
            for(int i=Log[3*n];i>=0;i--){
                if(max(r[i][v],r[i][u])-min(l[i][u],l[i][v])+1>=n) continue;
                int nu=rmq_l.query(l[i][u],r[i][v]);
                int nv=rmq_r.query(l[i][u],r[i][v]);
                u=nu;v=nv; 
                ans+=1<<i;
            }
            ans++;
            printf("%d ",ans);
        }
        puts("");
        return 0;
    }
    
  • 相关阅读:
    页面实现文件的下载
    微信小程序拉起登录的操作
    css3之border-radius理解
    web前端常用网站--更新中
    小程序中遇见文件过大的话就需要分包
    JS中的“&&”与“&”和“||”“|”有什么区别?
    ts中有时莫名报错
    浏览器解析JavaScript的原理
    在vue中axios的问题
    eslint的规则
  • 原文地址:https://www.cnblogs.com/jasony/p/13817541.html
Copyright © 2011-2022 走看看