【POJ2480】Longge's problem

【问题描述】

    求sigma(gcd(i,n)),1 <= i <= n.(n <= 10^9)

【分析】

    枚举i必然TLE。

    换个角度,我们枚举gcd(i,n) = k,然后统计满足gcd(i,n) = k的i的个数。

    gcd(i,n) = k的个数为phi(n/k)。phi(n/k)表示1到n/k中与n/k互质的个数。若一个数j与n/k互质,则j * k 与 n 的gcd为k。

    于是sigma(gcd(i,n)) = sigma(k * phi(n /k)),k | n。

    这样我们只要枚举n的约数就行了。但实际上这样复杂度还是很高,我们可以优化。我们可以考虑将枚举约数变为枚举质因子。

    N = p1^k1  *  p2^k2  *  ... *   pn^kn。令n1 = p1 ^ k1。若有一个约数为p1 ^ i。(由于phi(p ^j) = p^j - p^(j -1),)当gcd(i,n1) = p1 ^ i ,sigma(gcd(i,n1)) = p1 ^ i * (p1 ^ (k1 - i) - p1^ (k1 - i - 1)) = p1 ^k1 - p1 ^ (k1 - 1)。结果与i无关,所以sigma(gcd(i,n1)) = k1×(P1^k1-P1^(k1-1))+P1^k1

    所以只要找到n的质因子,然后分别算出,相乘起来就好了。

 

【代码】

    数论题就是这样,代码短。

    

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n;
int get_ans(long long n)
{
    long long res = 1;
    for (long long i = 2;i * i <= n;i ++)
    {
        if (n % i != 0) continue;
        long long num = 0,tmp = 1;
        while (n % i == 0)
        {
            tmp *= i;
            num ++;
            n /= i;
        }
        res *= num * (tmp - tmp/i) + tmp;
    }
    if (n > 1) res *= 2 * n - 1;
    return res;
}
int main()
{
    while (scanf("%lld",&n) != EOF)
        printf("%lld\n",get_ans(n));
}

 

posted @ 2013-01-20 21:48  N_C_Derek  阅读(158)  评论(0编辑  收藏  举报