简单
题目
传送门
题意:
做法:
中等
Sumdiv
传送门
题意:给定
a
a
a 和
b
b
b,求
a
b
a^b
ab 的约数和,对9901取模(0 <= a, b <= 50000000)
做法:对一个极大的数求约数和,很显然是要先将数字分解成素数幂的乘积,然后计算约数和,公式为
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
c
1
)
∗
(
1
+
p
2
+
p
2
2
+
.
.
.
+
p
2
c
2
)
∗
.
.
.
.
.
.
(1 + p1 + p1^2 + ... + p1^{c1}) * (1 + p2 + p2^2 + ... + p2^{c2}) * ......
(1+p1+p12+...+p1c1)∗(1+p2+p22+...+p2c2)∗......
根据 b 的数据可以算出 ci 的区间为 [b, b * 26](26 是由 a 的范围得出的),所以如果暴力有很大可能超时,经过实践验证确实是会超时,需要更优的时间。
应当尽可能的将每一项的计算时间缩短,有两种快速算出该式子的方法
首先是等比数列求和公式,
(
q
n
+
1
−
1
)
/
(
q
−
1
)
(q^{n+1}- 1) / (q - 1)
(qn+1−1)/(q−1)。这个公式做法非常简单,用快速幂和逆元就可以快速算出,但是对这题来说有一个坑点,这道题的模数是9901,对于素数 p 来说,p - 1 如果是 9901 的倍数,求逆元时就会返回 0,所以要对 (p - 1) % 9901 = 0 的情况特判,此时 p % 9901 = 1,求和公式直接变成 (c + 1)。
第二种方法就是递归求等比数列,用折半的思想递归,根据当前数列的数量奇偶使用不同的折半方法
LL get_(LL x, LL y)
{
if(y == 0) return 1;
else if(y % 2) return (get_(x, y / 2) * (1 + qmi(x, y / 2 + 1))) % mod;
else return (get_(x, y / 2 - 1) * (1 + qmi(x, y / 2 + 1)) + qmi(x, y / 2)) % mod;
}