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;
}
原文地址:https://www.cnblogs.com/aoxuets/p/5506829.html