BZOJ2226:LCMSum(欧拉函数)

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

Solution

$\sum_{i=1}^{n}lcm(i,n)$
$=\sum_{i=1}^{n}\frac{i\times n}{gcd(i,n)}$
$=\frac{1}{2}(\sum_{i=1}^{n-1}\frac{i\times n}{gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\times n}{gcd(i,n)})+n$
因为$gcd(a,b)=gcd(a-b,b)$,所以上面的两个$\sum$可以合起来。
$=\frac{1}{2}\sum_{i=1}^{n-1}\frac{n^2}{gcd(i,n)}+n$
设$gcd(i,n)=d$,把式子改为枚举$d$,那么与$n$的$gcd$为$d$的数有$φ(\frac{n}{d})$个。
$=\frac{1}{2}\sum_{d|n}\frac{n^2\times φ(\frac{n}{d})}{d}+n$
设$d'=\frac{n}{d}$,上下约分一下
$=\frac{1}{2}\sum_{d'|n}d'\times φ(d')+n$
预处理出$φ$数组,然后枚举每一个约数去计算它对它所有倍数的贡献,复杂度是调和级数的$O(nlogn)$。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define N (1000009)
 5 #define MAX (1000000)
 6 #define LL long long
 7 using namespace std;
 8 
 9 inline int read()
10 {
11     int x=0,w=1; char c=getchar();
12     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
13     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
14     return x*w;
15 }
16 
17 LL T,n,cnt,phi[N],ans[N],vis[N],prime[N];
18 
19 void Preprocess()
20 {
21     phi[1]=1;
22     for (int i=2; i<=MAX; ++i)
23     {
24         if (!vis[i]) prime[++cnt]=i, phi[i]=i-1;
25         for (int j=1; j<=cnt && i*prime[j]<=MAX; ++j)
26         {
27             vis[i*prime[j]]=1;
28             if (i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1);
29             else {phi[i*prime[j]]=phi[i]*prime[j]; break;}
30         }
31     }
32     for (int i=1; i<=MAX; ++i)
33         for (int j=i; j<=MAX; j+=i)
34             ans[j]+=i*phi[i]/2;
35     for (int i=1; i<=MAX; ++i) ans[i]=ans[i]*i+i;
36 }
37 
38 int main()
39 {
40     Preprocess();
41     T=read();
42     while (T--) n=read(), printf("%lld\n",ans[n]);
43 }
posted @ 2019-02-13 18:42  Refun  阅读(362)  评论(0编辑  收藏  举报