https://vjudge.net/problem/UVA-11426#author=0
求 SUM{ gcd(i,j) | 1<=i<j<=n}, n<4000001。
令f(n)=gcd(1,n)+gcd(2,n)+...+gcd(n-1,n),
则 S(n)=f(2)+f(3)+...+f(n) 即为我们所求答案,问题转化为求解f(n)。
可以看出对于f(n)的所有项的答案一定是n的因子,我们不妨令g(x,i)表示因子i对应的f(n)里的项x的个数,
那么f(n)=SUM{ i*g(x,i) | i为n的因子且0<x<n} 有gcd(x,n)==i --> gcd(x/i,n/i)==1 ,所以因子i对应的x的个数就
等价于与n/i互质且小于n/i的数的个数,这个就可以用phi来求解了。
在求f的时,一开始是用的O(N*sqrt(N))来一个一个找会T,太蠢了。只要和打表phi一样利用类似于埃筛
的方法就可以降到O(N*log(N))了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const int maxn=4000001; 5 LL f[maxn]; 6 int phi[maxn]; 7 void init(){ 8 phi[1]=1; 9 int m=sqrt(maxn+0.5); 10 for(int i=2;i<maxn;++i){ 11 if(!phi[i]){ 12 for(int j=i;j<maxn;j+=i){ 13 if(!phi[j]) phi[j]=j; 14 phi[j]=phi[j]/i*(i-1); 15 } 16 } 17 } 18 for(int i=1;i<maxn;++i){ 19 for(int j=i*2;j<maxn;j+=i){ 20 f[j]+=i*phi[j/i]; 21 } 22 } 23 for(int i=3;i<maxn;++i) f[i]+=f[i-1]; 24 } 25 int main(){ 26 init(); 27 int n; 28 while(scanf("%d",&n)&&n){ 29 printf("%lld ",f[n]); 30 } 31 return 0; 32 }