题意
传送门 POJ 1845
题解
分解质因数
A
=
p
1
e
1
p
2
e
2
…
p
n
e
n
A=p_1^{e_1}p_2^{e_2}\dots p_n^{e_n}
A=p1e1p2e2…pnen,则约数和为
(
1
+
p
1
+
⋯
+
p
1
e
1
)
(
1
+
p
2
+
⋯
+
p
2
e
2
)
…
(
1
+
p
n
+
⋯
+
p
n
e
n
)
(1+p_1+\dots +p_1^{e_1})(1+p_2+\dots +p_2^{e_2})\dots (1+p_n+\dots +p_n^{e_n})
(1+p1+⋯+p1e1)(1+p2+⋯+p2e2)…(1+pn+⋯+pnen)
逆元
对于质因数 p i p_i pi,根据等比数列求和公式,括号内求和为 p i e i B + 1 − 1 p i − 1 \frac{p_i^{e_iB+1}-1}{p_i-1} pi−1pieiB+1−1 分子项快速幂求解,分母项逆元求解。对于 p i m o d m = 1 p_i\ mod\ m =1 pi mod m=1 的情况需要特殊处理,因为此时 p i − 1 p_i-1 pi−1 不存在逆元。对于正整数 N N N,至多有一个大于等于 N \sqrt N N 的质因子,那么逆元打表处理 [ 1 , N ] [1,\sqrt N] [1,N] 的部分,对于超出这个范围的部分,利用费马小定理进行快速幂求逆元。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
#define mod 9901
typedef map<int, int> mp;
int A, B, inv[mod];
mp prime_factor(int n)
{
mp res;
for (int i = 2; i * i <= n; ++i)
{
while (n % i == 0)
{
++res[i];
n /= i;
}
}
if (n != 1)
res[n] = 1;
return res;
}
int mod_pow(int x, int n)
{
int res = 1;
x %= mod;
while (n)
{
if (n & 1)
res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
int get_inv(int n)
{
if (n < mod)
return inv[n];
return mod_pow(n, mod - 2);
}
int main()
{
inv[1] = 1;
for (int i = 2; i < mod; ++i)
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
scanf("%d%d", &A, &B);
mp fac = prime_factor(A);
int res = 1;
for (mp::iterator it = fac.begin(); it != fac.end(); ++it)
{
int p = it->first, e = it->second * B;
if (p % mod != 1)
res = res * (mod_pow(p, e + 1) + mod - 1) % mod * get_inv(p - 1) % mod;
else
res = res * (e % mod + 1) % mod;
}
printf("%d\n", res);
return 0;
}
分治
考虑质因数
p
i
p_i
pi,若
e
i
e_i
ei 为奇数,设其括号内求和为
s
u
m
(
p
,
e
)
sum(p,e)
sum(p,e),则有
s
u
m
(
p
,
e
)
=
(
1
+
p
+
⋯
+
p
⌊
e
/
2
⌋
)
+
(
p
⌊
e
/
2
⌋
+
1
+
⋯
+
p
e
)
=
(
1
+
p
⌊
e
/
2
⌋
+
1
)
×
s
u
m
(
p
,
⌊
e
/
2
⌋
)
sum(p,e)=(1+p+\dots+p^{\lfloor e/2\rfloor})+(p^{\lfloor e/2\rfloor+1}+\dots +p^e)=(1+p^{\lfloor e/2\rfloor+1})\times sum(p,\lfloor e/2\rfloor)
sum(p,e)=(1+p+⋯+p⌊e/2⌋)+(p⌊e/2⌋+1+⋯+pe)=(1+p⌊e/2⌋+1)×sum(p,⌊e/2⌋) 指数为偶数,将
p
i
e
i
p_i^{e_i}
piei 加入答案后将
e
i
e_i
ei 减一处理为奇数情况即可。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
#define mod 9901
typedef map<int, int> mp;
int A, B;
mp prime_factor(int n)
{
mp res;
for (int i = 2; i * i <= n; ++i)
{
while (n % i == 0)
{
++res[i];
n /= i;
}
}
if (n != 1)
res[n] = 1;
return res;
}
int mod_pow(int x, int n)
{
int res = 1;
x %= mod;
while (n)
{
if (n & 1)
res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
int sum(int p, int e)
{
if (!e)
return 1;
int res = 0;
if (!(e & 1))
res += mod_pow(p, e), --e;
e /= 2, res += (1 + mod_pow(p, e + 1)) * sum(p, e);
return res % mod;
}
int main()
{
scanf("%d%d", &A, &B);
mp fac = prime_factor(A);
int res = 1;
for (mp::iterator it = fac.begin(); it != fac.end(); ++it)
{
int p = it->first, e = it->second * B;
res = res * sum(p, e) % mod;
}
printf("%d\n", res);
return 0;
}