用自己的语言简单总结一下…加深理解。
题意:
Aria正面临算设课程的考试。
设
F
(
n
)
=
∏
i
=
1
n
∏
j
=
1
i
j
=
∏
i
=
1
n
i
!
F(n) = \prod_{i=1}^n\prod_{j=1}^{i}j = \prod_{i=1}^ni!
F(n)=i=1∏nj=1∏ij=i=1∏ni!
对于给定的n,m(其中n为质数),求F(
n
m
n^m
nm)中质因子n的出现次数,即求一个最大的非负整数e满足
n
e
n^e
ne整除F(
n
m
n^m
nm)。
由于是算设课的考试,答案当然是对
1
0
9
+
7
10^9+7
109+7取模的。
思路:
首先此题需要基于一个重要的数论知识点:
对于一个数
n
n
n,所包含的某个因子
m
m
m的次数是:
int calc(int n,int m){
int ans = 0;
while(n){
ans += n/m;
n = n/m;
}
return ans;
}
证明:
令
k
=
n
/
m
k = n/m
k=n/m
因为:
n
!
=
1
∗
2
∗
3
∗
.
.
.
n
n! = 1*2*3*...n
n!=1∗2∗3∗...n
试着将因子m提出,则一定有:(C为一个不含因子m的数)
n
!
=
(
m
∗
(
2
∗
m
)
∗
(
3
∗
m
)
.
.
.
(
k
∗
m
)
)
∗
C
n! = (m*(2*m)*(3*m)...(k*m)) * C
n!=(m∗(2∗m)∗(3∗m)...(k∗m))∗C
=
k
!
∗
m
k
∗
C
\ \ \ \ = k! * m^k * C
=k!∗mk∗C
所以
k
k
k一定是最后所求个数的一部分。
另一部分则是
k
!
k!
k!中所包含因子
m
m
m的个数。递归处理即可。
证毕。
记
c
a
l
c
(
n
,
m
)
calc(n,m)
calc(n,m)为
n
!
n!
n!中所含因子
m
m
m的个数。
因为
n
n
n为质数,则只需要单独考虑
1
−
n
m
1-n^m
1−nm中每个数所含因子
n
n
n个数的和。
a n s = ∑ i = 1 n m c a l c ( i , n ) ans = \sum_{i=1}^{n^m}calc(i,n) ans=i=1∑nmcalc(i,n)
由上面的证明的数论知识,我们易得:
对于
i
∈
[
k
n
,
k
n
+
n
−
1
]
i \in [kn,kn+n-1]
i∈[kn,kn+n−1] ,
c
a
l
c
(
i
,
n
)
calc(i,n)
calc(i,n)相同
故我们考虑将
1
−
n
m
1-n^m
1−nm中的所有数每
n
n
n个分为一组,则一组中所有数对答案的贡献相同。
对于
n
m
n^m
nm则需要特殊考虑,故答案可以化简为:
a
n
s
=
c
a
l
c
(
n
m
,
n
)
+
∑
i
=
1
n
m
−
1
c
a
l
c
(
i
,
n
)
ans = calc(n^m,n) + \sum_{i=1}^{n^m-1}calc(i,n)
ans=calc(nm,n)+i=1∑nm−1calc(i,n)
=
∑
i
=
0
m
−
1
n
i
+
n
∗
∑
i
=
1
n
m
−
1
−
1
c
a
l
c
(
i
∗
n
,
n
)
= \sum_{i=0}^{m-1}n^i + n*\sum_{i=1}^{n^{m-1}-1}calc(i*n,n)
=i=0∑m−1ni+n∗i=1∑nm−1−1calc(i∗n,n)
因为:
c
a
l
c
(
i
∗
n
,
n
)
=
i
+
c
a
l
c
(
i
,
n
)
calc(i*n,n) = i + calc(i,n)
calc(i∗n,n)=i+calc(i,n)
所以:
a
n
s
=
n
m
−
1
n
−
1
+
n
∗
(
∑
i
=
1
n
m
−
1
−
1
i
+
∑
i
=
1
n
m
−
1
−
1
c
a
l
c
(
i
,
n
)
)
ans = \frac{n^m-1}{n-1} + n*(\sum_{i=1}^{n^{m-1}-1} i + \sum_{i=1}^{n^{m-1}-1}calc(i,n) )
ans=n−1nm−1+n∗(i=1∑nm−1−1i+i=1∑nm−1−1calc(i,n))
对于括号里面的第二项,可以视为一个子问题递归处理,即得:
a
n
s
=
n
m
−
1
n
−
1
+
1
2
∗
(
n
m
(
n
m
−
1
−
1
)
+
n
m
(
n
m
−
2
−
1
)
+
.
.
.
+
n
m
(
n
−
1
)
)
ans = \frac{n^m-1}{n-1} + \frac{1}{2}*(n^m(n^{m-1}-1) + n^m(n^{m-2}-1) + ... +n^m(n-1))
ans=n−1nm−1+21∗(nm(nm−1−1)+nm(nm−2−1)+...+nm(n−1))
=
n
m
−
1
n
−
1
+
1
2
∗
n
m
∗
∑
i
=
1
m
−
1
(
n
i
−
1
)
= \frac{n^m-1}{n-1} + \frac{1}{2}*n^m*\sum_{i=1}^{m-1}(n^i-1)
=n−1nm−1+21∗nm∗i=1∑m−1(ni−1)
=
n
m
−
1
n
−
1
+
n
m
2
(
n
m
−
1
n
−
1
−
m
)
= \frac{n^m-1}{n-1} + \frac{n^m}{2}(\frac{n^m-1}{n-1} - m)
=n−1nm−1+2nm(n−1nm−1−m)
快速幂+逆元即可。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll fast_pow(ll n,ll m){
ll res = 1;
while(m){
if(m&1) res = res*n%mod;
n = n*n%mod;
m >>= 1;
}
return res;
}
int main(){
ll n,m;
scanf("%lld%lld",&n,&m);
ll res = (fast_pow(n,m)-1)*fast_pow(n-1,mod-2)%mod;
ll ans = (res + (fast_pow(n,m)*fast_pow(2,mod-2)%mod*(res-m)%mod))%mod;
if(ans<0) ans += mod;
printf("%lld\n",ans);
return 0;
}