/** 题目:GCD - Extreme (II) 链接:https://vjudge.net/contest/154246#problem/O 题意: for(i=1;i<N;i++) for(j=i+1;j<=N;j++) { G+=gcd(i,j); } 思路: 设f[n] = gcd(1,n)+gcd(2,n)+gcd(3,n)+...+gcd(n-1,n); s[n] = f[1]+f[2]+...+f[n]; 则:s[n] = f[n]+s[n-1]; f[n]的约数个数一般少于n-1个。所以如果可以以约数归类,就可以减少计算量。 设:gcd(n,i)表示 gcd(x,n) = i 时候的x的个数。(i为n的约数) 又:gcd(x,n)=i => gcd(x/i,n/i)=1;那么x/i的个数为(n/i)的欧拉函数值phi(n/i); 那么:f[n] = sum(i*phi(n/i)) (i为n的约数) 求每个f[n]不需要对每一个n单独求约数。 可以利用素数筛法类似的做法来处理。 参考思路:lrj算法经训练指南P125 */ #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int maxn = 4e6+100; ll f[maxn], s[maxn]; int phi[maxn]; void phiTable() { for(int i = 1; i < maxn; i++) phi[i] = i; for(int i = 2; i < maxn; i+=2) phi[i]/=2; for(int i = 3; i < maxn; i+=2){ if(phi[i]==i){ for(int j = i; j < maxn; j+=i){ phi[j] = phi[j]/i*(i-1); } } } } void init() { for(int i = 1; i < maxn; i++){ for(int j = i*2; j < maxn; j+=i){ f[j] += i*phi[j/i]; } } for(int i = 2; i < maxn; i++) s[i] = s[i-1]+f[i]; } int main() { int T, cas=1, N; phiTable(); init(); while(scanf("%d",&N)==1&&N) { printf("%lld\n",s[N]); } return 0; }