CF1575G GCD Festival
\(\sum\sum gcd(i,j) \times gcd(a_i,a_j)\)
考虑枚举这个 \(gcd(i,j)\) 。
\(\sum_d \varphi(d)\sum_{i|d}\sum_{j|d} gcd(a_i,a_j)\)
考虑后者等同于计算\(\sum_i\sum_j gcd(a_i,a_j)\)
我们考虑枚举约数 \(d\),那么会 \(d | gcd\) 的情况为 \((\sum[d | a_i]) ^ 2\)
考虑我们要求的是最大公约数,而非约数。
但是我们有\(x = \sum_{d|x}\varphi(x)\)
我们在情况数前加上一个系数即可。
转而求
\(\sum_d \varphi(d)\sum_t \varphi(t) (\sum[t | a_{k * d}]) ^ 2\)
那么预处理出因数,我们枚举 \(d\) ,然后 \(O(nln)\) 的遍历 \(a_i\) ,然后一次 \(d(n)\) 的处理一个数。
那么复杂度为预处理\(O(nln)\),计数复杂度\(O(\sum \lfloor\frac{n}{i} \rfloor d(i)) \leq O(Max{d(u)}nln)\)
#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<queue>
#define ll long long
#define N 100005
#define mod ((ll)1e9 + 7)
int n,a[N];
int phi[N];
int vis[N];
int Cnt,pri[N];
std::vector<int>Q[N];
inline void sieve(){
phi[1] = 1;
for(int i = 2;i < N;++i){
if(!vis[i])
phi[i] = i - 1,pri[++Cnt] = i;
for(int j = 1;pri[j] * i < N && j <= Cnt;++j){
vis[i * pri[j]] = 1;
if(i % pri[j] == 0){
phi[i * pri[j]] = phi[i] * pri[j];
break;
}else{
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
}
}
for(int i = 1;i < N;++i)
for(int j = 1;j * i < N;++j)
Q[i * j].push_back(i);
}
ll ans = 0;
int cnt[N];
#define p(x) ((x >= mod) ? x - mod : x)
inline void del(int u){
// std::cout<<u<<std::endl;
ll now = 0;
for(int i = u;i <= n;i += u){
for(int j = 0;j < Q[a[i]].size();++j){
now = p(now + p(p((p(cnt[Q[a[i]][j]] * 2) % mod + 1)) * phi[Q[a[i]][j]]) % mod);
cnt[Q[a[i]][j]] ++ ;
}
}
for(int i = u;i <= n;i += u){
for(int j = 0;j < Q[a[i]].size();++j){
cnt[Q[a[i]][j]] = 0 ;
}
}
ans = p(ans + 1ll * phi[u] * p(now) % mod);
}
int main(){
sieve();
scanf("%d",&n);
for(int i = 1;i <= n;++i)
scanf("%d",&a[i]);
for(int i = 1;i <= n;++i)
del(i);
std::cout<<ans<<std::endl;
}