假设现在有两个自然数
A
A
A 和
B
B
B,
S
S
S 是
A
B
A^B
AB 的所有约数之和。
请你求出
S
m
o
d
9901
S\ mod\ 9901
S mod 9901 的值是多少。
输入格式
在一行中输入用空格隔开的两个整数 A 和 B。
输出格式
输出一个整数,代表 Smod9901 的值。
数据范围
0
≤
A
,
B
≤
5
×
1
0
7
0 \leq A,B \leq 5 \times 10^7
0≤A,B≤5×107
输入样例
2 3
输出样例
15
注意: A A A 和 B B B 不会同时为 0 0 0
①分析
约数相关公式 已知: N = p 1 α 1 ⋅ p 2 α 2 . . . p k α k 约数个数 = ( α 1 + 1 ) ⋅ ( α 2 + 1 ) . . . ( α k + 1 ) 约数之和 = ( p 1 0 + p 1 + p 1 2 + . . . p 1 α 1 ) ⋅ ( p 2 0 + p 2 + p 2 2 + . . . p 2 α 2 ) . . . ( p k 0 + p k + p k 2 + . . . p k α k ) 约数相关公式\\ 已知:N=p_1^{\alpha_1}·p_2^{\alpha_2}...p_k^{\alpha_k}\\ 约数个数=(\alpha_1+1)·(\alpha_2+1)...(\alpha_k+1)\\ 约数之和=(p_1^0+p_1+p_1^2+...p_1^{\alpha_1})·(p_2^0+p_2+p_2^2+...p_2^{\alpha_2})...(p_k^0+p_k+p_k^2+...p_k^{\alpha_k})\\ 约数相关公式已知:N=p1α1⋅p2α2...pkαk约数个数=(α1+1)⋅(α2+1)...(αk+1)约数之和=(p10+p1+p12+...p1α1)⋅(p20+p2+p22+...p2α2)...(pk0+pk+pk2+...pkαk)
本题求的是 A B 可以先将 A 进行因式分解 = p 1 α 1 ⋅ p 2 α 2 . . . p k α k 则 A B = p 1 α 1 B ⋅ p 2 α 2 B . . . p k α k B ,就可以使用约数之和公式求解 下面要解决的就是 p 1 0 + p 1 + p 1 2 + . . . p 1 k − 1 怎么求,直接算会超时 法一:等比数列求和公式 = p k − 1 p − 1 ,分子用快速幂, 1 p − 1 就是求 p − 1 关于 9901 的逆元 法二:递归 = s u m ( p , k ) ,看其能否转化为更小的子问题 ① k 为偶数 s u m ( p , k ) = p 0 + p 1 + . . . + p k 2 − 1 + p k 2 ( p 0 + p 1 + . . . + p k 2 − 1 ) = ( 1 + p k 2 ) s u m ( p , k 2 ) ② k 为奇数 s u m ( p , k ) = p 0 + p ( p 0 + p 1 + . . . + p k − 2 ) = 1 + p s u m ( p , k − 1 ) = s u m ( p , k − 1 ) + p k − 1 本题求的是A^B\\ 可以先将A进行因式分解=p_1^{\alpha_1}·p_2^{\alpha_2}...p_k^{\alpha_k}\\ 则A^B=p_1^{\alpha_1B}·p_2^{\alpha_2B}...p_k^{\alpha_kB},就可以使用约数之和公式求解\\ 下面要解决的就是p_1^0+p_1+p_1^2+...p_1^{k-1}怎么求,直接算会超时\\ 法一:等比数列求和公式=\frac{p^k-1}{p-1},分子用快速幂,\frac{1}{p-1}就是求p-1关于9901的逆元\\ 法二:递归=sum(p,k),看其能否转化为更小的子问题\\ ①k为偶数sum(p,k)=p^0+p^1+...+p^{\frac{k}{2}-1}+p^{\frac{k}{2}}(p^0+p^1+...+p^{\frac{k}{2}-1})=(1+p^{\frac{k}{2}})sum(p,\frac{k}{2})\\ ②k为奇数sum(p,k)=p^0+p(p^0+p^1+...+p^{k-2})=1+p\ sum(p,k-1)=sum(p,k-1)+p^{k-1} 本题求的是AB可以先将A进行因式分解=p1α1⋅p2α2...pkαk则AB=p1α1B⋅p2α2B...pkαkB,就可以使用约数之和公式求解下面要解决的就是p10+p1+p12+...p1k−1怎么求,直接算会超时法一:等比数列求和公式=p−1pk−1,分子用快速幂,p−11就是求p−1关于9901的逆元法二:递归=sum(p,k),看其能否转化为更小的子问题①k为偶数sum(p,k)=p0+p1+...+p2k−1+p2k(p0+p1+...+p2k−1)=(1+p2k)sum(p,2k)②k为奇数sum(p,k)=p0+p(p0+p1+...+pk−2)=1+p sum(p,k−1)=sum(p,k−1)+pk−1
②代码
#include <cstdio>
const int MOD = 9901;
int qmi(int a, int k)
{
int res = 1;
a %= MOD;
while (k)
{
if (k & 1)
res = res * a % MOD;
a = a * a % MOD;
k >>= 1;
}
return res;
}
int sum(int p, int k)
{
if (k == 1)
return 1;
else if (k % 2 == 0)
return (1 + qmi(p, k / 2)) * sum(p, k / 2) % MOD;
else
return (sum(p, k - 1) + qmi(p, k - 1)) % MOD;
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
int res = 1;
for (int i = 2; i * i <= a; i++)
if (a % i == 0)
{
int p = 0;
while (a % i == 0)
{
a /= i;
p++;
}
res = res * sum(i, p * b + 1) % MOD;
}
if (a != 1)
res = res * sum(a, b + 1) % MOD;
if (a == 0)
res = 0;
printf("%d\n", res);
return 0;
}
③细节分析
-
快速幂
int qmi(int a, int k) { int res = 1; a %= MOD; // a可能会很大,a*a就会爆int while (k) { if (k & 1) res = res * a % MOD; a = a * a % MOD; k >>= 1; } return res; }
-
将a分解质因子
int res = 1; // 答案 for (int i = 2; i * i <= a; i++) if (a % i == 0) { int p = 0; // 当前质因子i的最高次数 while (a % i == 0) { a /= i; p++; } res = res * sum(i, p * b + 1) % MOD; }
-
a != 1
说明还存在一个的质因子a,其次数为1if (a > 1) res = res * sum(a, b + 1) % MOD;
-
sum(i, p * b + 1)
为公式里面 p k α k B = i p b p_k^{\alpha_kB}=i^{p\ b} pkαkB=ip b这一项,推出的公式中sum的第二个参数为最高次幂加一 -
递推着求 p k α k B = i p b p_k^{\alpha_kB}=i^{p\ b} pkαkB=ip b
int sum(int p, int k) { if (k == 1) // k=1即次数为0,值为1 return 1; else if (k % 2 == 0) return (1 + qmi(p, k / 2)) * sum(p, k / 2) % MOD; else return (sum(p, k - 1) + qmi(p, k - 1)) % MOD; }