问题
分析
首先要求在
[
2
,
N
!
]
[2,N!]
[2,N!]内和M!互素的数的个数
由于最大公约数的性质,
g
c
d
(
k
,
M
!
)
=
g
c
d
(
M
!
,
k
%
M
!
)
gcd(k,M!)=gcd(M!,k\%M!)
gcd(k,M!)=gcd(M!,k%M!),对于k>M!,k和M!互素等价于(k%M!)和M!互素,由于N>=M,所以N!是M!的整数倍数,那么整个区间内和M!互素的数的个数就是[1,M!]内和M!互素的数的个数的
N
!
/
M
!
倍
N!/M!倍
N!/M!倍,现在只对
k
∈
[
1
,
M
!
]
k\in [1,M!]
k∈[1,M!]内的数字求和M!互素的个数,所以使用phifac[k]表示小于k!的且和k!互素的数量,然后phifac[m]就是所求
根据欧拉phi函数推导可知:
如果k是素数
p
h
i
f
a
c
[
k
]
=
p
h
i
f
a
c
[
k
−
1
]
∗
(
k
−
1
)
phifac[k]=phifac[k-1]*(k-1)
phifac[k]=phifac[k−1]∗(k−1),如果k不是素数,
p
h
i
f
a
c
[
k
]
=
p
h
i
f
a
c
[
k
−
1
]
∗
k
phifac[k]=phifac[k-1]*k
phifac[k]=phifac[k−1]∗k
最后还要减去1
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <utility>
using namespace std;
typedef long long ll;
const ll mod=100000007LL,maxn=10000000+1;
ll n,m;
int vis[maxn],phifac[maxn]; //phifac[n]=phi[n!]
//vis[i]==0代表i是素数,1代表不是
void getPrime(){
int m=sqrt(maxn+0.5);
for(int i=2;i<=m;++i){
if(vis[i]==0){
for(int j=i*i;j<maxn;j+=i){
vis[j]=1;
}
}
}
}
int main(void){
getPrime();
//计算所有的phifac[k]的值
phifac[1]=1;
for(int i=2;i<=maxn;++i){
phifac[i]=(long long)phifac[i-1]*((vis[i]==0)?(i-1):i)%mod;
}
while(scanf("%lld%lld",&n,&m)==2 && n){
ll ans=phifac[m]; //查表,计算出1-m!中和m!互素的有多少个
for(int i=m+1;i<=n;++i){
ans=ans*i%mod; //乘以n!/m!,将结果扩展到1-n!区间中
}
printf("%lld\n",(ans-1+mod)%mod); //去除数字1
}
return 0;
}