这也是训练赛上的一个题目,题目的要求很简单,就是那个代码所展示的,然后,然后当时就不会了,后来才知道可以用欧拉函数求gcd(i,j);
先说一下如何分析这个题目
我们令f(n) = gcd(1, n) + gcd(2, n) + ... + gcd(n-1, n)
则对应的结果s(n) = f(2) + f(3) + ... + f(n)
所以s(n) = s(n-1)+f(n)
因此我们只需求出所有的f(n),在递推即可
取g(n, i)表示小于n且与n的gcd值等于i的数x的个数(gcd(n, x) = i)
则f(n) = 1*gcd(n, 1) + 2*gcd(n ,2) + ...
而gcd(n, x) = i即gcd(n/i, x/i) = 1
所以g(n, i) == phi(n/i)
这个当时自己就不会,说实话,以现在的水平,理解还是有点问题。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define MAXN 4000001
using namespace std;
int phi[MAXN+10];
LL f[MAXN+10], s[MAXN+10];
void phi_table(int n)
{
memset(phi, 0, sizeof(phi));
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);
}
}
}
return ;
}
int main(void)
{
int n;
phi_table(MAXN);
memset(s, 0, sizeof(s));
memset(f, 0, sizeof(f));
//cout<<phi[12]<<endl;
for(int i=1; i<=MAXN; ++i)
{
for(int j=i*2; j<=MAXN; j+=i)
f[j] += i*phi[j/i];
}
s[2] = f[2];
for(int i=3; i<=MAXN; ++i)
s[i] = s[i-1]+f[i];
while(~scanf("%d", &n) && n)
{
cout << s[n] << endl;
}
}