BZOJ2226: [Spoj 5971] 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
1
2
5
Sample Output
1
4
55
4
55
HINT
Constraints
1 <= T <= 300000
1 <= n <= 1000000
题解Here!
题目要求:$$Ans=\sum_{i=1}^nlcm(i,n)$$。
乍一看,很像懵逼钨丝反演,但是只有一个$\sum$。。。
那就慢慢推式子。。。
把那个$lcm$换成$gcd$:$$Ans=\sum_{i=1}^n\frac{in}{gcd(i,n)}=n\sum_{i=1}^n\frac{i}{gcd(i,n)}$$
习惯性地枚举$gcd$:$$Ans=n\sum_{d|n}\sum_{i=1}^n\frac{i}{d}[gcd(i,n)==d]$$
转变一下$i$:$$Ans=n\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}i\times [gcd(i,\frac{n}{d})==1]$$
然后因为$d|n$,所以$d==\frac{n}{d}$,那么:$$Ans=n\sum_{d|n}\sum_{i=1}^di\times [gcd(i,d)==1]$$
我们要求小于$d$且与$d$互素的所有自然数之和。
根据欧拉函数的性质:小于$n$且与$n$互素的所有自然数之和为$\frac{n\times \varphi(n)}{2}$。
原式可化为:$$Ans=n\sum_{d|n}\frac{d\times \varphi(d)}{2}$$
于是直接线性筛出$\varphi(i)$,每个数暴力算到它的倍数里去,就可以预处理出答案了。
复杂度是$O(n\log_2n+T)$。
我也不知道为什么别人写的$O(n+T\sqrt{n})$的都能卡过,我只能写$O(n\log_2n+T)$的,我的常数真的这么大吗。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #define MAXN 1000010 using namespace std; int n; int k=0,prime[MAXN],phi[MAXN]; long long sum[MAXN],ans[MAXN]; bool np[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } void make(){ int m=MAXN-10; phi[1]=1; for(int i=2;i<=m;i++){ if(!np[i]){ prime[++k]=i; phi[i]=i-1; } for(int j=1;j<=k&&prime[j]*i<=m;j++){ np[prime[j]*i]=true; if(i%prime[j]==0){ phi[prime[j]*i]=phi[i]*prime[j]; break; } phi[prime[j]*i]=phi[i]*phi[prime[j]]; } } sum[1]=1; for(int i=2;i<=m;i++)sum[i]=(long long)i*phi[i]/2; for(int i=1;i<=m;i++) for(int j=i;j<=m;j+=i) ans[j]+=sum[i]; for(long long i=1;i<=m;i++)ans[i]*=i; } int main(){ int t=read(); make(); while(t--){ n=read(); printf("%lld\n",ans[n]); } return 0; }