Description
Given the value of N, you will have to find the value of G. The meaning of G is given in the following code
G=0;
for(i=1;i<=N;i++)
for(j=i+1;j<=N;j++)
G+=gcd(i,j);
/*Here gcd() is a function that finds the greatest common divisor of the two input numbers*/
题意:输入正整数n,求gcd(1,2)+gcd(1,3)+gcd(2,3)+...+gcd(n-1,n),即所有满足1<=i<j<=n的数对(i,j)所对应的gcd(i,j)之和。
分析(源自《算法竞赛入门经典训练指南》):
设f(n)=gcd(1,n)+gcd(2,n)+...+gcd(n-1,n),则所求答案为S(n)=f(2)+f(3)+...+f(n)。只需求出f(n),就可以推出所有答案:S(n)=S(n-1)+f(n) 即 f(n)=f(n-1)+f(n)。因此,本题的重点在于如何计算f(n)。
注意到所有gcd(x,n)的值都是n的约数,可以按照这个约数进行分类,用g(n,i)表示满足gcd(x,n)=i且x<n的正整数x的个数,则f(n)=sum{i*g(n,i)|i是n的约数}。注意到gcd(x,n)=i的重要条件是gcd(x/i,n/i)=1,因此满足条件的x/i有 phi(n/i)个,说明g(n,i)=phi(n/i)。【phi(n)表示不超过n且和n互素的整数的个数】
如果依次计算f(n),需要对每个n枚举它的约数i,速度较慢,但如果把思路逆过来,对于每个i枚举它的倍数n(并且更新f(n)的值),时间复杂度讲降为与素数筛法同阶。具体代码如下。
The input file contains at most 20000 lines of inputs. Each line contains an integer N (1<N <1000001). The meaning
of N is given in the problem statement. Input is terminated by a line containing a single zero.
Output
For
each line of input produce one line of output. This line contains the value of G for the corresponding N. The value of G will fit in a 64-bit signed integer.
Sample
Input
10
100
200000
0
Sample Output
67
13015
143295493160
<span style="font-size:18px;">#include <cstdio>
#include <algorithm>
#include <cstring>
const int maxn=1000101;
typedef long long LL;
using namespace std;
int phi[maxn+1];
void phi_table(int n) //用类似筛法的方法求phi[]数组
{
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);
}
}
LL f[maxn+1];
int main()
{
phi_table(maxn);
memset(f,0,sizeof(f));
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=3; i<=maxn; i++)
f[i]+=f[i-1];
int n;
while(~scanf("%d",&n)&&n)
printf("%I64d\n",f[n]);
return 0;
}</span>