【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)); }