• 连续区间的最大公约数


    连续区间的最大公约数

     

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    #define pa pair<int,int>
    using namespace std;
    typedef long long LL;
     
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
     
    const int N = 200005;
    int gcd(int a,int b) { return b == 0 ? a : gcd(b, a % b); }
    struct Node {
        int len, g; LL cnt; vector< pa > pre, suf;
        Node() { cnt = 0; }
        Node (int v) {
            pre.push_back(pa(v, 1)); suf.push_back(pa(v, 1));
            g = v, cnt = 0, len = 1;
        }
    }T[N << 2];
    int a[N];
     
    #define fi first
    #define se second
    #define mp make_pair
    void Merge(vector<pa> &a,vector<pa> &b) {
        for (int i = 0; i < (int)b.size(); ++i) {
            pa p = b[i];
            if (p.fi % a.back().fi == 0) a.back().se += p.se;
            else a.push_back(pa(gcd(p.fi, a.back().fi), p.se));
        }
    }
    LL Calc(vector<pa> &a, vector<pa> &b,int g) {
        LL res = 0;
        int sz = b.size() - 1, sum = 0;
        for (int i = 0; i <= sz; ++i) sum += b[i].se;
        for (int i = 0; i < (int)a.size(); ++i) {
            pa p = a[i];
            while (sz >= 0 && gcd(p.fi, b[sz].fi) == g) sum -= b[sz --].se;
            res += 1ll * p.se * sum;
        }
        return res;
    }
    Node operator + (Node A, Node B) {
        Node res;
        res.g = gcd(A.g, B.g);
        res.cnt += (res.g == A.g ? A.cnt : 1ll * A.len * (A.len + 1) / 2);
        res.cnt += (res.g == B.g ? B.cnt : 1ll * B.len * (B.len + 1) / 2);
        res.len = A.len + B.len;
        res.pre = A.pre, res.suf = B.suf;
        Merge(res.pre, B.pre);
        Merge(res.suf, A.suf);
        res.cnt += Calc(A.suf, B.pre, res.g);
        return res;
    }
    void build(int l,int r,int rt) {
        if (l == r) { T[rt] = Node(a[l]); return ; }
        int mid = (l + r) >> 1;
        build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1);
        T[rt] = T[rt << 1] + T[rt << 1 | 1];
    }
    Node query(int l,int r,int rt,int L,int R) {
        if (L <= l && r <= R) return T[rt];
        int mid = (l + r) >> 1;
        if (R <= mid) return query(l, mid, rt << 1, L, R);
        else if (L > mid) return query(mid + 1, r, rt << 1 | 1, L, R);
        else return query(l, mid, rt << 1, L, R) + query(mid + 1, r, rt << 1 | 1, L, R);
    }
    void solve() {
        int n = read(), m;
        for (int i = 1; i <= n; ++i) a[i] = read();
        build(1, n, 1);
        m = read(); Node ans;
        while (m --) {
            int l = read(), r = read();
            ans = query(1, n, 1, l, r);
            printf("%d %lld
    ", ans.g, 1ll * ans.len * (ans.len + 1) / 2 - ans.cnt);
        }
    }
    int main() {
        for (int T = read(), i = 1; i <= T; ++i) {
            printf("Case #%d:
    ", i);
            solve();
        }
        return 0;
    }
  • 相关阅读:
    页面打开 抛出w3wp.exe 中发生未处理异常
    link
    带下拉子菜单的导航菜单
    横向列表菜单
    Codeforces Round #640 (Div. 4)
    【剑指Offer】06. 从尾到头打印链表
    【剑指Offer】65. 不用加减乘除做加法
    【剑指Offer】15. 二进制中1的个数
    【剑指Offer】03. 数组中重复的数字(哈希)
    【LeetCode】50. Pow(x, n)(快速幂)
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10453490.html
Copyright © 2020-2023  润新知