题目描述

f(n) = GCD(1, n) + GCD(2, n) + GCD(3, n) + ~ ~ ~ + GCD(n - 1, n).

 

输入

每行一个整数N (1 < N < 4000000),输入0的时候终止.

输出

对于输入的每一行输出要求的和.

样例输入

3176
17681
13080
0

样例输出

12684
17680
182220






我们假设gcd(n,i) = k,则gcd(n/k,i/k) = 1。即假设gcd(n/k, x ) = 1,则gcd(n,x*k) = k。gcd(n,i) = k,k的取值是确定的,即n的所有因子,所以,满足gcd(n/k,x) = 1个x的个数乘以k即为所有满足gcd(n,i) = k 的和。因此就转化为n/k的欧拉函数的值乘以k的所有的和。

举个例子12来说,12的因子为1,2,3,4,6,12,则和为12/1的欧拉函数值*1 + 12/2的欧拉函数值 * 2 + 12/3的欧拉函数值 * 3 + 12/4的欧拉函数值 * 4 + 12/6的欧拉函数值*6 + 12/12 的欧拉函数值 * 12。

 

我写的代码超时了... 无奈。

#include<cstdio>
#include<cmath>
int eular(int n)
{
    int ret=1,i;
    for(i=2;i*i<=n;i++){
        if(n%i==0){
            n/=i,ret*=i-1;
            while(n%i==0)
            n/=i,ret*=i;
        }
    }
    if(n>1)
        ret*=n-1;
    return ret;
}
long long a[200000];
int main()
{
    int n;

    while(scanf("%d", &n) && n){
        long long sum = 0, l = 0;
        //int p = sqrt(n * 1.0);
        for(int i = 1; i <= n; i++){
            if(n % i == 0){
                a[++l] = i;
            }
        }
        for(int i = 1; i < l; i++){
            long long m = n / a[i];
            sum += eular(m) * a[i];
        }
        printf("%lld\n", sum);
    }
    return 0;
}
View Code

 

这是学长的代码, 表示看不懂。。。

#include<stdio.h>
#include<string.h>
#define A  4000001
int p[A],ans[A];
int main()
{
    int N,i,j;
    memset(p,0,sizeof(p));
    memset(ans,0,sizeof(ans));
    p[1]=1;
    for(i=2;i<A;i++)       //p[n]表示[1~n]与n互质的个数
    if(!p[i])
    for(j=i;j<A;j+=i)
    {
        if(!p[j])   p[j]=j;
        p[j]=p[j]/i*(i-1);
    }
    for(i=1;i<A;i++)      //求结果
    for(j=i+i;j<A;j+=i)
    ans[j]+=i*p[j/i];
    while(scanf("%d",&N),N)
    printf("%d\n",ans[N]);
}
View Code