序列
题面:
给定一个序列,对于一个区间,其价值为不在区间内的数之间的两两最大公约数的最大值,请求出所有长度<=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; }