题意:给出正整数n,求gcd(1,2)+gcd(1,3)+gcd(2,3)……+gcd(n-1,n),即求求sum( gcd(i,j) , 1<=i<j<=n )1<n<4000001
思路:
设f[n] = gcd(1,n)+gcd(2,n)+……+gcd(n-1,n)
所以要求的结果就是s[n] = f[1] + f[2] +……+ f[n],所以结果s[n] = s[n-1] + f[n]
gcd(x,n)=i是n的约数(x<n),所以可以按照这个约数进行分类。设gcd(x,n)=i的个数为g(n,i),则有f[n] = sum( i*g(n,i) )。
这个gcd(x,n) = i等价于gcd(x/i,n/i) = 1,因此满足条件的 x/i 有 phi(n/i) 个(欧拉函数的定义),所以就是欧拉函数的求phi表了。
然后求f[n],这儿要对于每个 i 枚举其倍数n
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 4000000;
typedef long long ll;
ll s[N+5],f[N+5];
int phi[N];
void phi_table(int n)
{
for(int i = 2;i <= n;i++)
phi[i] = 0;
phi[1] = 1;
for(int i = 2;i <= n;i++)
{
if(!phi[i])
{
for(int j = i;j <= n;j+=i)
{
if(!phi[j])
phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
}
}
int main()
{
phi_table(N);
memset(f,0,sizeof(f));
for(int i = 1;i <= N;i++)
for(int n = i*2;n <= N;n+=i)
f[n] += i * phi[n / i];
//预处理
s[2] = f[2];
for(int n = 3;n <= N;n++)
s[n] = s[n-1] + f[n];
int n;
while(~scanf("%d",&n) && n)
{
printf("%lld\n",s[n]);
}
return 0;
}