序列

  题面:

  给定一个序列,对于一个区间,其价值为不在区间内的数之间的两两最大公约数的最大值,请求出所有长度<=n-2的区间的价值之和。

  代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#define maxn 200005
using namespace std;
struct node
{
    int l, r, mx, set;
    long long s;
} tree[maxn * 4];
void upd(int rt, int x)
{
    tree[rt].mx = tree[rt].set = x;
    tree[rt].s = 1LL * (tree[rt].r - tree[rt].l + 1) * x;
}
void pushup(int rt)
{
    tree[rt].mx = max(tree[rt << 1].mx, tree[rt << 1 | 1].mx);
    tree[rt].s = tree[rt << 1].s + tree[rt << 1 | 1].s;
}
void pushdown(int rt)
{
    if (tree[rt].set != -1)
    {
        upd(rt << 1, tree[rt].set);
        upd(rt << 1 | 1, tree[rt].set);
        tree[rt].set = -1;
    }
}
void build(int rt, int l, int r)
{
    tree[rt].l = l, tree[rt].r = r;
    tree[rt].set = -1;
    if (l == r)
    {
        tree[rt].mx = tree[rt].s = l - 1;
        return;
    }
    build(rt << 1, l, l + r >> 1);
    build(rt << 1 | 1, (l + r >> 1) + 1, r);
    pushup(rt);
}
void update(int rt, int l, int r, int x)
{
    if (tree[rt].r < l || r < tree[rt].l)
        return;
    if (l <= tree[rt].l && tree[rt].r <= r)
    {
        upd(rt, x);
        return;
    }
    pushdown(rt);
    update(rt << 1, l, r, x);
    update(rt << 1 | 1, l, r, x);
    pushup(rt);
}
long long sum(int rt, int l, int r)
{
    if (tree[rt].r < l || r < tree[rt].l)
        return 0;
    if (l <= tree[rt].l && tree[rt].r <= r)
        return tree[rt].s;
    pushdown(rt);
    return sum(rt << 1, l, r) + sum(rt << 1 | 1, l, r);
}
int search(int rt, int x)
{
    if (tree[rt].mx < x)
        return -1;
    if (tree[rt].l == tree[rt].r)
        return tree[rt].l;
    pushdown(rt);
    return tree[rt << 1].mx >= x ? search(rt << 1, x) : search(rt << 1 | 1, x);
}
int n;
long long solve(int l, int r, int h)
{
    int pos = search(1, h);
    if (pos == -1)
        pos = n + 1;
    if (pos <= l)
        return 0;
    r = min(r, pos - 1);
    long long ans = 1LL * (r - l + 1) * h - sum(1, l, r);
    update(1, l, r, h);
    return ans;
}
vector <int> G[maxn];
int read()
{
    char ch = getchar();
    int cnt = 0;
    while (ch < '0' || '9' < ch)
        ch = getchar();
    while ('0' <= ch && ch <= '9')
    {
        cnt = cnt * 10 + ch - '0';
        ch = getchar();
    }
    return cnt;
}
int main()
{
    freopen("sequence.in", "r", stdin);
    freopen("sequence.out", "w", stdout);
    n = read();
    int mx = 0;
    for (int i = 1; i <= n; ++ i)
    {
        int a = read();
        mx = max(mx, a);
        for (int j = 1; j * j <= a; ++ j)
            if (a % j == 0)
            {
                G[j].push_back(i);
                if (j != a / j)
                    G[a / j].push_back(i);
            }
    }
    build(1, 1, n);
    long long ans = 0;
    for (int i = mx; i; -- i)
        if (G[i].size() >= 2)
        {
            sort(G[i].begin(), G[i].end());
            int l = G[i][0], r = G[i][G[i].size() - 1], a = G[i][1], b = G[i][G[i].size() - 2];
            long long cnt = solve(1, l, b - 1) + solve(l + 1, a, r - 1) + (a < n ? solve(a + 1, n, n) : 0);
            ans += cnt * i;
        }
    cout << ans << endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

 

posted @ 2019-06-28 17:31  paopo  阅读(252)  评论(0编辑  收藏  举报