• #4702. gcd


    题目描述

    题解

    考虑从大到小枚举 $gcd$ ,假设 $gcd$ 的倍数出现的位置从小到大为 $p_1,p_2,...,p_{t-1},p_t$ ,那它影响的区间为 $[1,p_{t-1}-1],[p_1+1,p_t-1],[p_2+1,n]$

    考虑对每个点 $l$ 维护一个右端点 $r$ 表示 $[l,u](lle u le r)$ 都被影响过了,每次计算答案的时候考虑用总区间数减去被影响过区间数,发现随着 $l$ 的增大 $r$ 是单调递增的,于是线段树上二分即可

    代码

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=2e5+5;
    int T,n,t,a[N],b[N],m,h[N<<2],tg[N<<2],g[N];
    LL s,f[N<<2]; struct O{int k,l,r;}S[25];
    #define Ls k<<1
    #define Rs k<<1|1
    #define mid ((l+r)>>1)
    void up(int k){
        f[k]=f[Ls]+f[Rs];
        h[k]=min(h[Ls],h[Rs]);
    }
    void push(int k,int l,int r,int v){
        h[k]=tg[k]=v;f[k]=1ll*(r-l+1)*v;
    }
    void down(int k,int l,int r){
        push(Ls,l,mid,tg[k]);
        push(Rs,mid+1,r,tg[k]);
        tg[k]=0;
    }
    void build(int k,int l,int r){
        tg[k]=0;if (l==r){f[k]=h[k]=l-1;return;}
        build(Ls,l,mid);build(Rs,mid+1,r);up(k);
    }
    void upd(int k,int l,int r,int L,int R,int v){
        if (L<=l && r<=R) return push(k,l,r,v);
        if (tg[k]) down(k,l,r);
        if (mid>=L) upd(Ls,l,mid,L,R,v);
        if (mid<R) upd(Rs,mid+1,r,L,R,v);
        up(k);
    }
    void find(int k,int l,int r,int L,int R){
        if (L<=l && r<=R){
            S[++t]=(O){k,l,r};return;
        }
        if (tg[k]) down(k,l,r);
        if (mid>=L) find(Ls,l,mid,L,R);
        if (mid<R) find(Rs,mid+1,r,L,R);
    }
    int get(int k,int l,int r,int v,LL &w){
        if (l==r){
            if (h[k]>=v) return l-1;
            else{w+=f[k];return l;}
        }
        if (tg[k]) down(k,l,r);
        if (h[Rs]>=v) return get(Ls,l,mid,v,w);
        else{
            w+=f[Ls];
            return get(Rs,mid+1,r,v,w);
        }
    }
    void work(int l,int r,int v){
        if (l>r) return;
        LL x=1ll*(r-l+1)*(r-l+2)/2;
        t=0;find(1,1,n,l,r);
        LL y=0;int u=r;
        for (int i=1;i<=t;i++){
            if (h[S[i].k]>=r){
                if (i>1) u=get(S[i-1].k,S[i-1].l,S[i-1].r,r,y);
                else u=l-1; break;
            }
            if (i>1) y+=f[S[i-1].k];
            if (i==t) u=get(S[i].k,S[i].l,S[i].r,r,y);
        }
        x-=(y+1ll*(r-u)*r-1ll*(l+r)*(r-l+1)/2+(r-l+1));
        if (l<=u) upd(1,1,n,l,u,r);s+=x*v;
    }
    void work(){
        scanf("%d",&n);
        build(1,1,n);m=0;s=0;
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]),
            b[a[i]]=i,m=max(m,a[i]);
        for (int v,i=m;i;i--){
            v=0;
            for (int j=i;j<=m;j+=i)
                if (b[j]) g[++v]=b[j];
            if (v<2) continue;
            sort(g+1,g+v+1);
            work(g[1]+1,g[v]-1,i);
            work(1,g[v-1]-1,i);
            work(g[2]+1,n,i);
        }
        for (int i=1;i<=m;i++) b[i]=0;
        printf("%lld
    ",s);
    }
    int main(){
        for (scanf("%d",&T);T--;work());
        return 0;
    }
  • 相关阅读:
    用户管理
    开机、重启、用户登录注销
    网络请求的封装
    Vuex
    Promise
    Vue Router(二)
    Vue Router(一)
    Vue CLI
    前端模块化-导入导出
    插槽
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12256497.html
Copyright © 2020-2023  润新知