poj1845 Sumdiv
Sumdiv
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 23172 | Accepted: 5769 |
Description
Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).
Input
The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.
Output
The only line of the output will contain S modulo 9901.
Sample Input
2 3
Sample Output
15
Hint
2^3 = 8.
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).
Source
分析:这道题有点复杂,涉及到约数嘛,肯定是先要分解一下,将原数变成唯一分解定律的表达形式,a = p1^x1*p2^x2*...*pn^xn,a^b = p1^x1b*p2^x2b*...*pn^xnb,那么约数和怎么求呢?如果把a^b的所有约数用唯一分解定律的表达形式写出来,就会发现p1和p2,p3,...,pn的所有的乘积的组合形式乘了一次,因式分解一下,可以得到sum = (1 + p1 + p1^2 + ... + p1^x1b) * (1 + p2 + ...+p2^x2b)*......
括号里的式子是一个等比数列,我们可以套用公式来计算,涉及到取模,就要求逆元,不过这个地方有点小技巧,如果求-1的逆元,答案是-1,但是程序给的是1,也就是说我们最好是求正数的逆元,等比数列求和公式上下同取负号就好了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int mod = 9901; long long cnt[100010],wh[100010],tot,ans = 1; int a,b; void exgcd(long long a,long long b,long long &x,long long &y) { if (!b) { x = 1; y = 0; return; } exgcd(b,a % b,x,y); long long t = x; x = y; y = t - (a / b) * y; return; } long long qpow(long long a,long long b) { long long ans = 1; while (b) { if (b & 1) ans = (ans * a) % mod; a = (a * a) % mod; b >>= 1; } return ans; } int main() { scanf("%d%d",&a,&b); for (int i = 2; i <= sqrt(a); i++) { if (a % i == 0) { wh[++tot] = i; while (a % i == 0) { a /= i; cnt[i]++; } } } if (a) { wh[++tot] = a; cnt[a]++; } for (int i = 1; i <= tot; i++) { long long x,y; exgcd(wh[i] - 1,mod,x,y); ans = (ans * (( qpow(wh[i],cnt[wh[i]] * b + 1) - 1)* x) % mod) % mod; } printf("%lld\n",ans); return 0; }