传送门:HDU-6102
题解:莫比乌斯函数+树状数组+离线操作
先对查询按R升序排序,从左到右枚举Ak,再枚举A1~Ak-1中Ak的倍数(因为是1~n的全排列,因此总枚举量为nlogn),得到B数组,将B数组中的数都除以Ak,并按照A中的下标从小到大排序,然后只要求B中所有GCD(Bi,Bj)==1(i<j)的二元组个数即可。
求二元组个数可以直接用莫比乌斯函数求得,对于Bi对答案的贡献为cnt[下标大于i且与Bi互质的Bj]*Ak
每次枚举Ak都要更新A1~Ak-1的贡献,因此可以用树状数组维护。总复杂度O(nlog^2n)
#include<bits/stdc++.h>
#define FIN freopen("in.txt","r",stdin);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;
struct Tree {
int n;
vector <LL> T ;
void init (int sz) {
T.clear();
n = sz;
T.resize(n + 1);
}
void add (int x, LL v) {
for (int i = x; i <= n; i += i & -i) T[i] += v;
}
LL sum (int x) {
if (x > n) x = n;
LL ret = 0;
for (int i = x; i > 0; i -= i & -i) ret += T[i];
return ret;
}
} te;
struct Query {
int l, r, id;
bool operator<(const Query& _A)const {
if (r != _A.r) return r < _A.r;
return l < _A.l;
}
} que[MX];
struct Array {
int val, index;
bool operator<(const Array& _A)const {
return index < _A.index;
}
} A[MX];
int sz, vis[MX], arr[MX];
bool prime[MX];
int mob[MX], p[MX];
vector<int> d[MX];
int num[MX];
void Mobius() {
int pnum = 0;
memset(prime, true, sizeof(prime));
mob[1] = 1;
for(int i = 2; i < MX; i++) {
if(prime[i]) {
p[pnum ++] = i;
mob[i] = -1;
}
for(int j = 0; j < pnum && (LL)i * p[j] < MX; j++) {
prime[i * p[j]] = false;
if(i % p[j] == 0) {
mob[i * p[j]] = 0;
break;
}
mob[i * p[j]] = -mob[i];
}
}
}
void presolve() {
for (int i = 1; i < MX; i++) {
for (int j = i; j < MX; j += i) {
d[j].push_back(i);
}
}
}
void solve(int k) { //A数组是Aj,B数组是Ai,i<j
for (int i = 1; i <= sz; i++) {
int t = A[i].val;
for (int j = 0; j < d[t].size(); j++) num[d[t][j]]++;
}
for (int i = 1; i <= sz; i++) {
LL cnt = 0;
int t = A[i].val;
for (int j = 0; j < d[t].size(); j++) num[d[t][j]]--;
for (int j = 0; j < d[t].size(); j++)
cnt += num[d[t][j]] * mob[d[t][j]];
te.add(A[i].index, cnt * k);
}
}
LL ans[MX];
int main() {
//FIN;
Mobius(); presolve();
int T, n, m;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
te.init(n);
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
vis[i] = 0;
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &que[i].l, &que[i].r);
que[i].id = i;
}
sort(que + 1, que + m + 1);
vis[arr[1]] = 1; vis[arr[2]] = 2;
for (int i = 1, k = 3; i <= m; i++) {
for (; k <= que[i].r; k++) {
sz = 0;
vis[arr[k]] = k;
for (int x = 2; x * arr[k] <= n; x++) {
if (vis[x * arr[k]]) {
A[++sz].val = x;
A[sz].index = vis[x * arr[k]];
}
}
sort(A + 1, A + sz + 1);
solve(arr[k]);
}
ans[que[i].id] = te.sum(que[i].r) - te.sum(que[i].l - 1);
}
for (int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
}
return 0;
}