/** 題目: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; }
