【题目】
Description
Given n, calculate the sum LCM(1,n) + LCM(2,n) + … + LCM(n,n), where LCM(i,n) denotes the Least Common Multiple of the integers i and n.
Input
The first line contains T the number of test cases. Each of the next T lines contain an integer n.
Output
Output T lines, one for each test case, containing the required sum.
Sample Input
3
1
2
5
Sample Output
1
4
55
Hint
Constraints 1 <= T <= 300000 1 <= n <= 1000000
【分析】
我们要求的是
∑ i = 1 n l c m ( i , n ) \sum_{i=1}^nlcm(i,n) i=1∑nlcm(i,n)
把 l c m lcm lcm 换成 g c d gcd gcd 就是
∑ i = 1 n i × n gcd ( i , n ) \sum_{i=1}^n\frac{i\times n}{\gcd(i,n)} i=1∑ngcd(i,n)i×n
这个式子可以巧妙的转换成
1 2 ( ∑ i = 1 n − 1 i × n gcd ( i , n ) + ∑ i = 1 n − 1 ( n − i ) × n gcd ( n − i , n ) ) + n \frac{1}{2}(\sum_{i=1}^{n-1}\frac{i\times n}{\gcd(i,n)}+\sum_{i=1}^{n-1}\frac{(n-i)\times n}{\gcd(n-i,n)})+n 21(i=1∑n−1gcd(i,n)i×n+i=1∑n−1gcd(n−i,n)(n−i)×n)+n
根据辗转相减法, gcd ( i , n ) = gcd ( n − i , n ) \gcd(i,n)=\gcd(n-i,n) gcd(i,n)=gcd(n−i,n),因此可以继续化简
1 2 ∑ i = 1 n − 1 n 2 gcd ( i , n ) + n \frac1 2\sum_{i=1}^{n-1}\frac{n^2}{\gcd(i,n)}+n 21i=1∑n−1gcd(i,n)n2+n
也就是说,我们现在的目标就是求出
∑ i = 1 n − 1 n 2 gcd ( i , n ) \sum_{i=1}^{n-1}\frac{n^2}{\gcd(i,n)} i=1∑n−1gcd(i,n)n2
我们枚举 gcd \gcd gcd,把式子转化成
∑ d ∣ n n 2 d ∑ i = 1 n − 1 [    gcd ( i , n ) = d    ] \sum_{d|n}\frac{n^2}{d}\sum_{i=1}^{n-1}[\;\gcd(i,n)=d\;] d∣n∑dn2i=1∑n−1[gcd(i,n)=d]
转换为 gcd = 1 \gcd=1 gcd=1 的形式
∑ d ∣ n n 2 d ∑ i = 1 , i ≠ n n d [    gcd ( i , n d ) = 1    ] \sum_{d|n}\frac{n^2}{d}\sum_{i=1,i\ne n}^{\frac{n}{d}}[\;\gcd(i,\frac{n}{d})=1\;] d∣n∑dn2i=1,i̸=n∑dn[gcd(i,dn)=1]
发现后面部分跟欧拉函数的解析式一样( φ ( n ) = ∑ i = 1 n [    gcd ( i , n ) = 1    ] \varphi(n)=\sum\limits_{i=1}^n[\;\gcd(i,n)=1\;] φ(n)=i=1∑n[gcd(i,n)=1])
用欧拉函数转换一下就是
∑ d ∣ n , d ≠ n n 2 × φ ( n d ) d \sum_{d|n,d\ne n}\frac{n^2\times \varphi(\frac{n}{d})}{d} d∣n,d̸=n∑dn2×φ(dn)
把一个 n n n 提出来,也就是
n ∑ d ∣ n , d ≠ n n d × φ ( n d ) = n ∑ d ∣ n , d ≠ 1 d × φ ( d ) n\sum_{d|n,d\ne n}\frac{n}{d}\times\varphi(\frac{n}{d})=n\sum_{d|n,d\ne1}d\times \varphi(d) nd∣n,d̸=n∑dn×φ(dn)=nd∣n,d̸=1∑d×φ(d)
然后线性筛出欧拉函数值,预处理一下就可以了。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
using namespace std;
bool mark[N];
int prime[N],phi[N];
long long ans[N];
void linear_sieves()
{
int i,j,sum=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false;phi[1]=1;
for(i=2;i<N;++i)
{
if(mark[i]) prime[++sum]=i,phi[i]=i-1;
for(j=1;j<=sum&&i*prime[j]<N;++j)
{
mark[i*prime[j]]=false;
if(i%prime[j]) phi[i*prime[j]]=phi[i]*phi[prime[j]];
else {phi[i*prime[j]]=phi[i]*prime[j];break;}
}
}
}
void prework()
{
int i,j;
for(i=1;i<N;++i)
for(j=2;i*j<N;++j)
ans[i*j]+=1ll*j*phi[j];
for(i=1;i<N;++i) ans[i]=ans[i]*i/2+i;
}
int main()
{
int n,i,x;
scanf("%d",&n);
linear_sieves();
prework();
for(i=1;i<=n;++i)
{
scanf("%d",&x);
printf("%lld\n",ans[x]);
}
return 0;
}