Label
欧拉函数
Description
给定整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1\leq n\leq 10^5) n(1≤n≤105),求:
∑ i = 1 n ∑ j = 1 n g c d ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j) i=1∑nj=1∑ngcd(i,j)
Solution
看上去此题所求又是一个反演的形式(其实此题可用反演解),但我们可以利用欧拉函数来分析。
有了poj2480的基础,我们已经知道: ∑ i = 1 n g c d ( i , n ) = ∑ d ∣ n d φ ( n d ) \sum_{i=1}^{n}gcd(i,n)=\sum_{d|n}d\varphi(\frac{n}{d}) i=1∑ngcd(i,n)=d∣n∑dφ(dn),则易得:
∑ i = 1 n ∑ j = 1 n g c d ( i , j ) = 2 ∑ i = 1 j ∑ j = 1 n g c d ( i , j ) − ∑ i = 1 n i = 2 ∑ i = 1 n ∑ d ∣ i d φ ( i d ) − ∑ i = 1 n i \sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j)=2\sum_{i=1}^{j}\sum_{j=1}^{n}gcd(i,j)-\sum_{i=1}^{n}i=2\sum_{i=1}^{n}\sum_{d|i}d\varphi(\frac{i}{d})-\sum_{i=1}^{n}i i=1∑nj=1∑ngcd(i,j)=2i=1∑jj=1∑ngcd(i,j)−i=1∑ni=2i=1∑nd∣i∑dφ(di)−i=1∑ni
而 ∑ i = 1 n ∑ d ∣ i d φ ( i d ) = ∑ d = 1 n ∑ i = 1 n φ ( i d ) = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ φ ( i ) \sum_{i=1}^{n}\sum_{d|i}d\varphi(\frac{i}{d})=\sum_{d=1}^{n}\sum_{i=1}^{n}\varphi(\frac{i}{d})=\sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i) i=1∑nd∣i∑dφ(di)=d=1∑ni=1∑nφ(di)=d=1∑ni=1∑⌊dn⌋φ(i)
(此步化简:考虑所有可能的 d d d的取值,进而考虑每种 d d d对答案的贡献)
所以, ∑ i = 1 n ∑ j = 1 n g c d ( i , j ) = 2 ( ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ φ ( i ) ) − n ( n + 1 ) 2 \sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j)=2(\sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i))-\frac{n(n+1)}{2} i=1∑nj=1∑ngcd(i,j)=2(d=1∑ni=1∑⌊dn⌋φ(i))−2n(n+1)
由于 ∑ i = 1 ⌊ n d ⌋ φ ( i ) \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(i) ∑i=1⌊dn⌋φ(i)可前缀和预处理,故算法整体复杂度为 O ( n ) O(n) O(n)。
Code
#include<cstdio>
#include<iostream>
#define ri register int
#define ll long long
using namespace std;
const int MAXN=1e5+20;
int N,prime[MAXN>>2],phi[MAXN],cnt;
ll ans,sum[MAXN];
bool isprime[MAXN];
void Phi()
{
isprime[1]=true; phi[1]=1;
for(ri i=2;i<=N;++i)
{
if(!isprime[i])
{
prime[++cnt]=i;
phi[i]=i-1;
}
for(ri j=1;j<=cnt&&i*prime[j]<=N;++j)
{
isprime[i*prime[j]]=true;
if(i%prime[j]==0) phi[i*prime[j]]=phi[i]*prime[j];
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
if(i%prime[j]==0) break;
}
}
}
int main()
{
scanf("%d",&N);
Phi();
for(ri i=1;i<=N;++i) sum[i]=sum[i-1]+(ll)phi[i];
for(ri d=1;d<=N;++d) ans+=(ll)d*sum[N/d];
ans=ans*2LL-(ll)N*(ll)(N+1)/2LL;
cout<<ans;
return 0;
}