题意大概就如代码上所说的,
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*/
/*这里gcd()是一个函数,二者中最大的公约数,输入数字*/
求i从1到n-1分别与i+1到n的最大公约数的和。
可以倒过来思考,就是求i从1到n-1与的最大公约数,(n的变化为1到n);
n每增加一个1,循环就多一个 可用公式表示。
G(n)=G(n-1)+
所以重点是求 , 这里可用for循环打个表,记录下n从1到 4000001的前缀和,最后直接输出即可。
虽说这里是求最大公约数,但直接用gcd(),还是容易超时,这里可以用欧拉函数dp[n]的方法来间接求最大公约数。
可知 gcd(i,n)=1,(i和n均为素数),
当i和n的最大公约数为k的时候,即gcd(i,n)=k,可以这样写 gcd(i/k,n/k)=1;
所以求出,每个数的欧拉函数,再遍历k的值,使得 dp[i*k]*k,
当n为素数的时候, =n-1;前面的数和它的最大公约数均为1,故累加得n-1,
代码如下:
#include<stdio.h>
#include<string.h>
#define LL long long
const int N=4e6+10;
LL dp[N];
LL a[N];
void init()
{
memset(dp,0,sizeof(dp));
dp[1]=1;
for(int i=2; i<=N; i++)//欧拉函数打表
{
if(!dp[i])
{
dp[i]=i-1;
for(int j=2*i; j<=N; j+=i)
{
if(!dp[j])
dp[j]=j;
dp[j]=dp[j]/i*(i-1);
}
}
for(int j=1;i*j<=N;j++)//设公约数为j,
a[i*j]+=dp[i]*j;
}
//for(int i=1;i<=30;i++)
// printf("%d\t",dp[i]);
}
int main()
{
LL n;
init();
for(int i=1; i<=N; i++)
a[i]+=a[i-1];
while(~scanf("%lld",&n)&&n)
printf("%lld\n",a[n]);
return 0;
}