题目链接:
UVA 11428 GCD - Extreme (II)
题意:
i<N j≤N
给定n求:G = ∑ ∑ GCD(i, j) (n <= 4000000)
i=1 j=i+1
分析:
令sum[n]为题式中答案。考虑递推
sum[n] = sum [n - 1] + gcd(1, n) + gcd(2, n) + gcd(3, n) + ... + gcd(n - 1, n)
令f[n] = gcd(1, n) + gcd(2, n) + gcd(3, n) + ... + gcd(n - 1, n).
设满足gcd(x, n) = t …①的x(x < n)的个数有h[t]个,显然x, t均是n的约数,又因为不包含gcd(n, n),所以t < n。
将等式①两边同除以t可得:gcd(x/t, n/t) = 1.所以h[t] = phi[n/t].
那么枚举n的约数可以得到:f[n] = ∑t*phi[[n/t]](t为n的所有约数) - n(相当于去掉gcd(n, n))
需要预处理f[n]然后对于每个n有:sum[i] = sum[i - 1] + f[i],sum[1] = 0;递推即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 4000010;
int n;
ll phi[MAX_N], f[MAX_N], sum[MAX_N];
void GetPhi()
{
memset(phi, 0, sizeof(phi));
phi[1] = 1;
for(int i = 2;i < MAX_N; i++){
if(phi[i] == 0){
for(int j = i; j < MAX_N; j += i){
if(phi[j] == 0) phi[j] = j;
phi[j] = phi[j] / i * (i - 1);
}
}
}
}
void init()
{
GetPhi();
memset(f, 0, sizeof(f));
for(int i = 1; i < MAX_N; i++){
for(int j = i; j < MAX_N; j += i){
f[j] += i * phi[j / i];
}
}
}
int main()
{
init();
while(~scanf("%d", &n) && n){
sum[1] = 0;
for(int i = 2; i <= n; i++){
sum[i] = sum[i - 1] + f[i] - i;
}
printf("%lld\n", sum[n]);
}
return 0;
}