zoukankan      html  css  js  c++  java
  • CF671C Ultimate Weirdness of an Array

    n<=200000个数(<=200000),问所有的f(i,j)的和,f(i,j)表示去掉区间i到j后的剩余的数字中任选两个数的最大gcd

    首先我们用(nxt_l)表示当(f(l,r)le i)时,(l)对应的右端点(r)最往左能取到哪里,初始时(nxt_l=l),如果不存在合法右端点就记(nxt_l=n+1)

    然后考虑从大到小枚举(i),当从(f(l,r)le i)变为(f(l,r)le i-1)时,我们需要删除(gcd=i)的贡献,找出(i)的倍数在原序列中的下标记为(x_1,x_2......x_m),而我们新得到的区间([l,nxt_l'])肯定是要满足包含(m-1)(x_i)的,不然答案就至少是(i)了,所以我们进行如下修改操作:

    • (lin(x_2,n])(nxt_l=n+1)

    • (lin(x_1,x_2])(nxt_l=max(nxt_l,x_m))

    • (lin[1,x_1])(nxt_l=max(nxt_l,x_{m-1}))

    2,3操作看似需要吉司机线段树来维护,但是我们冷静下来分析一波,(nxt)数组一定是单调不降,所以一定是进行区间的一段前缀覆盖,直接线段树上二分修改复杂度就是(O(nlogn))

    其实开始时(O(nsqrt n))处理每个数倍数的位置就已经足够了,但是也可以优化,因为我们最多只需要2个开头的和2个结尾的,那么直接合并(i)的倍数的集合就好了,复杂度是(O(nlogn)),我比较懒就直接写的第一种QAQ

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #define zrt k << 1
    #define yrt k << 1 | 1
    const int N = 2e5;
    using namespace std;
    int n,a[N + 5],Mx;
    long long ans,las;
    vector <int> d[N + 5];
    struct Seg
    {
        long long sm[N * 5 + 5],tag[N * 4 + 5];
        int mi[N * 4 + 5],mx[N * 4 + 5];
        void pushup(int k)
        {
            sm[k] = sm[zrt] + sm[yrt];
            mi[k] = min(mi[zrt],mi[yrt]);
            mx[k] = max(mx[zrt],mx[yrt]);
        }
        void build(int k,int l,int r)
        {
            if (l == r)
            {
                mx[k] = mi[k] = sm[k] = l;
                return;
            }
            int mid = l + r >> 1;
            build(zrt,l,mid);
            build(yrt,mid + 1,r);
            pushup(k);
        }
        void cha(int k,int l,int r,int z)
        {
            sm[k] = 1ll * (r - l + 1) * z;
            mi[k] = mx[k] = z;
            tag[k] = z;
        }
        void pushdown(int k,int l,int r,int mid)
        {
            if (tag[k])
            {
                cha(zrt,l,mid,tag[k]);
                cha(yrt,mid + 1,r,tag[k]);
                tag[k] = 0;
            }
        }
        void modify(int k,int l,int r,int x,int y,int z)
        {
            if (x > y)
                return;
            if (r < x || l > y || mi[k] >= z)
                return;
            if (l >= x && r <= y && mx[k] <= z)
            {
                cha(k,l,r,z);
                return;
            }
            if (l == r)
            {
                sm[k] = mi[k] = mx[k] = z;
                return;
            }
            int mid = l + r >> 1;
            pushdown(k,l,r,mid);
            modify(zrt,l,mid,x,y,z);
            modify(yrt,mid + 1,r,x,y,z);
            pushup(k);
        }
    }tree;
    int main()
    {
        scanf("%d",&n);
        for (int i = 1;i <= n;i++)
            scanf("%d",&a[i]),Mx = max(Mx,a[i]);
        for (int i = 1;i <= n;i++)
            for (int j = 1;j * j <= a[i];j++)
                if (a[i] % j == 0)
                {
                    d[j].push_back(i);
                    if (j * j != a[i])
                        d[a[i] / j].push_back(i);
                }
        tree.build(1,1,n);
        las = 1ll * n * (n + 1) - tree.sm[1];
        int x1,x2,x3,x4;
        for (int i = Mx;i >= 1;i--)
        {
            if (d[i].size() < 2)
                continue;
            x1 = *d[i].begin();
            x2 = *(d[i].begin() + 1);
            x3 = *(d[i].end() - 2);
            x4 = *(d[i].end() - 1);
            tree.modify(1,1,n,x2 + 1,n,n + 1);
            tree.modify(1,1,n,x1 + 1,x2,x4);
            tree.modify(1,1,n,1,x1,x3);
            ans += (las - (1ll * n * (n + 1) - tree.sm[1])) * i;
            las = 1ll * n * (n + 1) - tree.sm[1];
        }
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    利用dockerfile定制镜像
    发布Docker 镜像到dockerhub
    Docker 停止容器
    133. Clone Graph
    132. Palindrome Partitioning II
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    127. Word Ladder
  • 原文地址:https://www.cnblogs.com/sdlang/p/13435078.html
Copyright © 2011-2022 走看看