求 G ( n ) = ∑ i = 1 n i g c d ( i , n ) G(n)=\sum_{i=1}^{n}\frac{i}{gcd(i,n)} G(n)=∑i=1ngcd(i,n)i 的值,其中 g c d ( i , n ) gcd(i,n) gcd(i,n) 为 i i i 和 n n n 的最大公约数。
输入数据以多组数据给出,数据组数不超过 1 0 5 10^5 105, 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1≤n≤106。
我们先考虑按 i = 1... n i=1...n i=1...n 中的 g c d ( i , n ) gcd(i,n) gcd(i,n) 分类,当 n = 6 n=6 n=6 时,分类如下图:
因此,对于上式的
G
(
n
)
G(n)
G(n) 也可以写成:
G
(
n
)
=
∑
d
∣
n
n
d
n
φ
(
d
n
)
G(n)=\sum_{d|n}^{n}\frac{d}{n}φ(\frac{d}{n})
G(n)=∑d∣nnndφ(nd),即
G
(
n
)
=
∑
d
∣
n
n
d
φ
(
d
)
G(n)=\sum_{d|n}^{n}dφ(d)
G(n)=∑d∣nndφ(d)。
定理: G ( n ) = ∑ d ∣ n n d φ ( d ) G(n)=\sum_{d|n}^{n}dφ(d) G(n)=∑d∣nndφ(d) 为积性函数。
证明:设有正整数 n , m n,m n,m 且互质,所以 n , m n,m n,m 的约数互不相同(不然最大公因数就不是 1 1 1),所以 n m nm nm 的约数个数为 n , m n,m n,m 约数个数的积。因为欧拉函数本身是积性函数,所以可得以下结论:
G ( n ) G ( m ) = ∑ i ∣ n n ∑ j ∣ m m i j φ ( i ) φ ( j ) = ∑ i ∣ n n ∑ j ∣ m m i j φ ( i j ) = G ( n m ) G(n)G(m)=\sum_{i|n}^n\sum_{j|m}^mijφ(i)φ(j)=\sum_{i|n}^n\sum_{j|m}^mijφ(ij)=G(nm) G(n)G(m)=i∣n∑nj∣m∑mijφ(i)φ(j)=i∣n∑nj∣m∑mijφ(ij)=G(nm)
其中枚举 i , j i,j i,j 后的 i j ij ij 项已经枚举了 n m nm nm 的所有约数,因此 G ( n ) G(n) G(n) 为积性函数。
众所周知,所有积性函数都可以用线性筛法递推得到。对于任意一个质数 x x x 来说, G ( x ) = ( x − 1 ) x + 1 G(x)=(x-1)x+1 G(x)=(x−1)x+1,这很容易通过式子证明。
当递推 i ∗ p r i m e [ j ] = k i*prime[j]=k i∗prime[j]=k 时,若 p r i m e [ j ] prime[j] prime[j] 不是 i i i 的质因子,那么直接有 G ( k ) = G ( i ) G ( p r i m e [ j ] ) G(k)=G(i)G(prime[j]) G(k)=G(i)G(prime[j])。
若 p r i m e [ j ] prime[j] prime[j] 是 i i i 的质因子,分两种情况:
-
i i i 不是 p r i m e [ j ] prime[j] prime[j] 为底数的幂。
我们从 i i i 中提取 i i i 最小质因子的指数 m i [ i ] mi[i] mi[i] 和幂 h i g h P o w [ i ] highPow[i] highPow[i]。由线性筛的原理得知, p r i m e [ j ] prime[j] prime[j] 也是 i i i 的最小质因子。令 A = h i g h P o w [ i ] ∗ p r i m e [ j ] , B = i ∗ p r i m e [ j ] / A A=highPow[i]*prime[j],B=i*prime[j]/A A=highPow[i]∗prime[j],B=i∗prime[j]/A,那么很容易递推 G ( i ∗ p r i m e [ j ] ) = G ( A ) G ( B ) G(i*prime[j])=G(A)G(B) G(i∗prime[j])=G(A)G(B)。 -
i i i 是 p r i m e [ j ] prime[j] prime[j] 为底数的幂。
若用上述方法,会得出 A = i ∗ p r i m e [ j ] , B = 1 A=i*prime[j],B=1 A=i∗prime[j],B=1,无法递推。设 k = i ∗ p r i m e [ j ] k=i*prime[j] k=i∗prime[j],利用之前的式子,很容易可知 G ( k ) = ∑ p = 0 m i [ k ] p r i m e [ j ] p φ ( p r i m e [ j ] p ) G(k)=\sum_{p=0}^{mi[k]}prime[j]^pφ(prime[j]^p) G(k)=∑p=0mi[k]prime[j]pφ(prime[j]p)。由欧拉函数的计算公式可知, φ ( p r i m e [ j ] p ) = p r i m e [ j ] p ( 1 − 1 p r i m e [ j ] ) φ(prime[j]^p)=prime[j]^p(1-\frac{1}{prime[j]}) φ(prime[j]p)=prime[j]p(1−prime[j]1)。因此,上述 G ( k ) G(k) G(k) 的公式可以用暴力实现。
其中 h i g h P o w [ ] highPow[] highPow[] 和 m i [ ] mi[] mi[] 都可以通过线性筛来实现。如果是这样,我们就可以不用计算欧拉函数了。
#include<bits/stdc++.h>
#define int long long
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
int n,t,x,prime[10000010],m,ans,g[10000010],highPow[10000010],mi[10000010],w[2][10000010];
bool b[10000010];
signed main()
{
scanf("%lld",&t);
n=10000000;
for(int i=2;i<=n;i++)
{
if(!b[i]) //没有被筛选过,说明 i 是质数
{
g[i]=i*(i-1)+1;
highPow[i]=i;
mi[i]=1;
prime[++m]=i;
}
for(int j=1;j<=m&&i*prime[j]<=n;j++)
{
int x=i*prime[j]; //k=x=i*prime[j]
b[x]=true; //筛选质数
if(i%prime[j]) //i 和 prime[j] 互质
{
int A=i,B=prime[j];
g[x]=g[A]*g[B];
highPow[x]=B;
mi[x]=1;
}
else
{
highPow[x]=highPow[i]*prime[j];
mi[x]=mi[i]+1;
int A=highPow[x];
int B=i*prime[j]/A;
if(B==1) //分情况,如果 i 是 prime[j] 的幂
{
w[0][0]=w[1][0]=1;
w[0][1]=prime[j];
w[1][1]=prime[j]-1;
for(int k=2;k<=mi[x];k++)
{
w[0][k]=w[0][k-1]*prime[j];
w[1][k]=w[1][k-1]*prime[j];
}
for(int k=0;k<=mi[x];k++)
{
g[x]+=w[0][k]*w[1][k];
}
}
else
{
g[x]=g[A]*g[B];
}
break;
}
}
}
while(t--)
{
scanf("%lld",&x);
if(x-1)printf("%lld\n",g[x]); //if(x-1)就是x不等于1
else printf("1\n");//特判 1 的情况
}
return 0;
}