Description
给定一个
n
排列,
Solution
首先先推一推柿子:
∑L≤i<j≤R(ai,aj)==∑L≤i<j≤R∑d|(ai,aj)d∑k|(aid,ajd)μ(k)∑L≤i<j≤R∑k|(ai,aj)∑d|kμ(kd)d
由莫比乌斯反演
id=φ∗1⇔φ=μ∗id
所以
∑L≤i<j≤R(ai,aj)=∑L≤i<j≤R∑k|(ai,aj)φ(k)
设约数
k
出现次数为
∑kφ(k)(∑d|ici)(∑d|jcj)=∑kφ(k)(∑d|ici)2
这个柿子用莫队暴力维护一下就好啦。
时间复杂度是 O(n32+nlnn) 的吧。
#include <bits/stdc++.h>
using namespace std;
const int N = 20202;
typedef long long ll;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
inline void read(int &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
int test, n, L, R, Pcnt, x, q, B;
ll res;
int a[N], c[N];
int prime[N], phi[N], vis[N];
int bl[N], pre[N];
ll ans[N];
struct Qry {
int l, r, id;
inline friend bool operator <(const Qry &a, const Qry &b) {
return bl[a.l] == bl[b.l] ? a.r < b.r : bl[a.l] < bl[b.l];
}
};
vector<int> fac[N];
Qry Q[N];
inline void Add(int pos, int x) {
static int fact, key; key = a[pos];
for (int i = 0; i < fac[key].size(); i++) {
fact = fac[key][i];
res -= (ll)phi[fact] * c[fact] * c[fact];
c[fact] += x;
res += (ll)phi[fact] * c[fact] * c[fact];
}
}
int main(void) {
read(test); phi[1] = 1;
for (int i = 2; i <= 20000; i++) {
if (!vis[i]) {
prime[++Pcnt] = i; phi[i] = i - 1;
}
for (int j = 1; j <= Pcnt && (x = i * prime[j]) <= 20000; j++) {
vis[x] = 1;
if (i % prime[j]) {
phi[x] = phi[i] * phi[prime[j]];
} else {
phi[x] = phi[i] * prime[j];
break;
}
}
}
for (int i = 1; i <= 20000; i++)
for (int j = i; j <= 20000; j += i)
fac[j].push_back(i);
for (int itisalongname = 1; itisalongname <= test; itisalongname++) {
memset(c, 0, sizeof c);
read(n); B = ceil(sqrt(n));
for (int i = 1; i <= n; i++) {
read(a[i]);
pre[i] = pre[i - 1] + a[i];
}
read(q);
for (int i = 1; i <= q; i++) {
read(Q[i].l); read(Q[i].r);
Q[i].id = i;
}
for (int i = 1; i <= n; i++)
bl[i] = (i - 1) / B + 1;
sort(Q + 1, Q + q + 1);
L = 1; R = 0; res = 0;
for (int i = 1; i <= q; i++) {
while (R < Q[i].r) Add(++R, 1);
while (R > Q[i].r) Add(R--, -1);
while (L > Q[i].l) Add(--L, 1);
while (L < Q[i].l) Add(L++, -1);
ans[Q[i].id] = (res - pre[R] + pre[L - 1]) >> 1;
}
printf("Case #%d:\n", itisalongname);
for (int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
}
return 0;
}