题目大意
给你两个数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;
else
return (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;
}
这个代码比线筛还简洁一些- -