假设一个数n可以拆成
n
=
p
1
a
1
∗
p
2
a
2
∗
.
.
.
∗
p
k
a
k
n=p_1^{a_1} * p_2^{a_2} *...*p_k^{a_k}
n=p1a1∗p2a2∗...∗pkak,
其中p是质数,如
36
=
2
2
∗
3
2
36=2^2*3^2
36=22∗32,
那么约数的和就是 ( p 1 0 + p 1 1 + . . . + p 1 a 1 ) ∗ ( p 2 0 + p 2 1 + . . . + p 2 a 2 ) ∗ . . . ∗ ( p k 0 + p k 1 + . . . + p k a k ) (p_1^0+p_1^1+...+p_1^{a_1})*(p_2^0+p_2^1+...+p_2^{a_2})*...*(p_k^0+p_k^1+...+p_k^{a_k}) (p10+p11+...+p1a1)∗(p20+p21+...+p2a2)∗...∗(pk0+pk1+...+pkak)
如36的约数之和就是 ( 1 + 2 + 2 2 ) ∗ ( 1 + 3 + 3 2 ) = 91 = 1 + 2 + 3 + 4 + 6 + 9 + 12 + 18 + 36 (1+2+2^2)*(1+3+3^2) = 91=1+2+3+4+6+9+12+18+36 (1+2+22)∗(1+3+32)=91=1+2+3+4+6+9+12+18+36。
因为所有约数都是由若干个这样的质数p组成的,而上面的乘法展开就是所有质数的组合。
以36为例:
(
1
+
2
+
2
2
)
∗
(
1
+
3
+
3
2
)
(1+2+2^2)*(1+3+3^2)
(1+2+22)∗(1+3+32)
1
=
1
∗
1
1=1*1
1=1∗1
2
=
2
∗
1
2=2*1
2=2∗1
…
12
=
2
2
∗
3
12=2^2*3
12=22∗3
18
=
2
∗
3
2
18=2*3^2
18=2∗32
36
=
2
2
∗
3
2
36=2^2*3^2
36=22∗32
用试除法统计所有数的所有质数个数 a i a_i ai,用式子 ( p 1 0 + p 1 1 + . . . + p 1 a 1 ) ∗ ( p 2 0 + p 2 1 + . . . + p 2 a 2 ) ∗ . . . ∗ ( p k 0 + p k 1 + . . . + p k a k ) (p_1^0+p_1^1+...+p_1^{a_1})*(p_2^0+p_2^1+...+p_2^{a_2})*...*(p_k^0+p_k^1+...+p_k^{a_k}) (p10+p11+...+p1a1)∗(p20+p21+...+p2a2)∗...∗(pk0+pk1+...+pkak)得到答案。
#include <iostream>
#include <unordered_map>
using namespace std;
long long cnt, ans = 1;
const int mod = 1e9 + 7;
int n, a;
unordered_map<int, int> primes;
int main() {
scanf("%d", &n);
while (n -- ) {
scanf("%d", &a);
for (int i = 2; i * i <= a; i ++ ) {
while (a % i == 0) {
a /= i;
primes[i] ++; // 各个数的约数个数相加
}
}
if (a > 1) primes[a] ++; // a是质数时
}
for (auto prime: primes) {
//printf("%d %d\n", prime.first, prime.second);
long long p = 1;
cnt = 0;
for (int i = 0; i <= prime.second; i ++ ) {
cnt = (cnt + p) % mod;
p = (p * prime.first) % mod; //计算p的1,2,3...次方
}
ans = (ans * cnt) % mod;
}
printf("%lld\n", ans);
return 0;
}
注意这边的取模,由模运算的规则
(
a
+
b
)
%
p
=
(
a
%
p
+
b
%
p
)
%
p
(a + b) \% p = (a \% p + b \% p) \% p
(a+b)%p=(a%p+b%p)%p
(
a
∗
b
)
%
p
=
(
a
%
p
∗
b
%
p
)
%
p
(a * b) \% p = (a \% p * b \% p) \% p
(a∗b)%p=(a%p∗b%p)%p
所以上述代码的结果是等价于最后再取模的。
注意到
p
1
0
+
p
1
1
+
.
.
.
+
p
1
a
1
=
(
(
p
1
+
1
)
∗
p
1
+
1
)
∗
p
1
+
1
)
∗
p
1
+
1....
p_1^0+p_1^1+...+p_1^{a_1}=((p_1+1)*p_1+1)*p_1+1)*p_1+1....
p10+p11+...+p1a1=((p1+1)∗p1+1)∗p1+1)∗p1+1....
总共进行
a
1
a_1
a1次
因此循环还可以改写成
for (auto prime: primes) {
cnt = 0;
for (int i = 0; i <= prime.second; i ++ ) {
cnt = (cnt * prime.first + 1) % mod;
}
ans = (ans * cnt) % mod;
}