zoukankan      html  css  js  c++  java
  • CodeForces 671C

    题意:

    给以一个定义, F(l, r) 的值表示序列 A[1:n]的子序列
    A[1....(l-1),(r+1)...n] 之中 任意两个数的最大公约数的最大值。
    

    Sum=i=1Nj=1N(F(i,j)),(ij)

    思路:

    英文题解
    大致解释一下:

        H[i] 表示 F(l, r) <= i 区间 (l,r) 的个数。
        V[A[i]] = { b1, b2, .... bk }, 其中 A[i] % bx == 0
        还有一个next 数组
        设 next[j] = k, 表示 F(l, k) <= i, k 尽可能的小。
        当然会有 k 不存在的时候, 则 next[j] = n+1;(为什么, 看下面)
        这时候可以知道 :
    

    H[i]=j=1N(nnext[j]+1)

        右端为 next[j] , 左端则有 n-next[j]+1种选择。
    

    Code:

    #include <bits/stdc++.h>
    #define lson l , m, rt<<1
    #define rson m+1, r, rt<<1|1
    using namespace std;
    typedef long long LL;
    const LL maxn = 200000 + 131;
    const LL MaxN = 200000;
    struct node {
        LL Max, Min;
        LL Sum, Flag;
    };
    
    node Node[maxn<<2];
    LL H[maxn], A[maxn], Idx[maxn];
    LL L1[maxn], L2[maxn], R1[maxn], R2[maxn];
    
    ///SegmentTree
    void PushUp(LL rt) {
        Node[rt].Max = max(Node[rt<<1].Max, Node[rt<<1|1].Max);
        Node[rt].Min = min(Node[rt<<1].Min, Node[rt<<1|1].Min);
        Node[rt].Sum = Node[rt<<1].Sum + Node[rt<<1|1].Sum;
    }
    void PushDown(LL l, LL r, LL rt) {
        LL m = (l + r) >> 1;
        if(Node[rt].Flag)
        {
            Node[rt<<1].Flag = Node[rt<<1].Max = Node[rt<<1].Min = Node[rt].Flag;
            Node[rt<<1|1].Flag = Node[rt<<1|1].Max = Node[rt<<1|1].Min = Node[rt].Flag;
            Node[rt<<1].Sum = Node[rt].Flag * (m - l + 1);
            Node[rt<<1|1].Sum = Node[rt].Flag * (r - m);
            Node[rt].Flag = 0;
        }
    }
    void Build(LL l, LL r, LL rt) {
        Node[rt].Flag = 0;
        if(l == r) {
            Node[rt].Max = Node[rt].Min = Node[rt].Sum = l;
            return ;
        }
        LL m = (l + r) >> 1;
        Build(lson), Build(rson);
        PushUp(rt);
    }
    void Update_section(LL L, LL R, LL val, LL l, LL r, LL rt) {
        if(L > R) return ;
        if(Node[rt].Min >= val) return ;
        if(L <= l and r <= R and Node[rt].Max <= val) {
            Node[rt].Flag = val;
            Node[rt].Min = Node[rt].Max = val;
            Node[rt].Sum = LL(r - l + 1) * LL(val);
            return ;
        }
        PushDown(l, r, rt);
        LL m = (l + r) >> 1;
        if(L <= m) Update_section(L, R, val, lson);
        if(R > m)  Update_section(L, R, val, rson);
        PushUp(rt);
    }
    /// Solve
    int main() {
         std::ios::sync_with_stdio(false);
         LL n;
         cin >> n;
         for(LL i = 1; i <= n; ++i) {
            cin >> A[i];
            Idx[A[i]] = i;
         }
         /// Get l(1, b1) -> bk-1, (b1,b2) -> bk, (b2, n) -> n+1
         for(LL i = 1; i <= MaxN; ++i)
         {
             for(LL j = i; j <= MaxN; j +=i)
             if(Idx[j])
             {
                 if(L1[i] == 0 or L1[i] > Idx[j]) L2[i] = L1[i], L1[i] = Idx[j];
                 else if(L2[i] == 0 or L2[i] > Idx[j]) L2[i] = Idx[j];
                 if(R1[i] < Idx[j]) R2[i] = R1[i], R1[i] = Idx[j];
                 else if(R2[i] < Idx[j]) R2[i] = Idx[j];
             }
         }
         /// Build Tree
         Build(1,n,1);
         for(LL i = MaxN; i > 0; --i)
         {
             if(L1[i] != R1[i])
             {
                 Update_section(1,L1[i],R2[i], 1, n, 1);
                 Update_section(L1[i]+1, L2[i], R1[i], 1, n, 1);
                 Update_section(L2[i]+1, n, n+1, 1, n, 1);
             }
             H[i] = LL(n*(n+1)) - Node[1].Sum;
             //cout << H[i] << endl;
         }
         LL Ans = 0;
         for(LL i = 1; i < MaxN; ++i)
            Ans += i * (H[i+1]-H[i]);
         cout << Ans <<endl;
         return 0;
    }
    
  • 相关阅读:
    properties文件不能输入中文
    java: bin里面的.class文件没有了怎么办
    LINUX 系统java自动化启动浏览器 提示:The driver is not executable: /home/pt/Downloads/googledriver/chromedriver_linux64/chromedriver
    MarkdownTest
    洛谷P5364 [SNOI2017]礼物 题解
    长链剖分
    左偏树(可并堆)
    Splay
    分层图最短路
    整体二分
  • 原文地址:https://www.cnblogs.com/aoxuets/p/5506829.html
Copyright © 2011-2022 走看看