POJ 1845 Sumdiv

来源:互联网 发布:vb filter 过滤 编辑:程序博客网 时间:2024/05/16 17:00

题目大意

给你两个数A,B(≤5*10^7),求A^B的所有约数之和(mod 9901)

解题思路

显然把A的所有质因数(p1,p2,......,pn)和质因数的最高幂次(k1,k2,......,kn)求出来之后求sigma(pi^0+pi^1+......+pi^(ki * B))并取模,即为题目所求
我的思路有两个错误。
一开始想用线性筛质数乱搞,结果发现内存不够。此题是2002年的题目,应该还没用到这么屌的东西- -
第二个错误,等比数列求和中有除法运算,除法不满足同余运算的各种运算律,如果要满足需要转化为逆元,但转化为逆元的条件是将要除的数与取模的数互质,这道题明显不保证一定互质。
看了网上别人的解题报告,用到的是二分法求等比数列之和,这个可以有!

Code

#include <iostream>#include <cstdio>#include <cmath>using namespace std;const int p = 9901;long long pos[10000], cnt[10000];long long power(long long a, long long b){int x = 1;while (b){if (b % 2) x = (x * a) % p;a = (a * a) % p; b /= 2;}return x;}long long calc(long long x, long long n){if (n == 0)return 1;if (n % 2 == 1)return (calc(x, n / 2) * (1 + power(x, n / 2 + 1))) % p;elsereturn (calc(x, n / 2 - 1) * (1 + power(x, n / 2 + 1)) + power(x, n / 2)) % p;}int main(){int A, B, n = 0;cin >> A >> B;int x = A;if (A <= 1){cout << A << endl;return 0;}else if (B == 0){cout << 1 << endl;return 0;}for (int i = 2; i <= int(sqrt(double(A))); i++){bool flag = false;pos[n] = i;while (x % i == 0){x /= i; cnt[n]++; flag = true;}if (flag) n++;}if (x > 1){pos[n] = x; cnt[n] = 1; n++;}long long ans = 1;for (int i = 0; i < n; i++){ans = (ans * calc(pos[i], cnt[i] * B)) % p;}cout << ans << endl;}
这个代码比线筛还简洁一些- -

0 0