题目链接 https://cn.vjudge.net/problem/UVA-11440
【题意】
输入整数
n
n
和 ,统计区间
[2,n!]
[
2
,
n
!
]
之间有多少个整数
x
x
满足 的所有素因子都大于
m (2<=n<=107,1<=m<=n,n−m<=105)
m
(
2
<=
n
<=
10
7
,
1
<=
m
<=
n
,
n
−
m
<=
10
5
)
答案对
100000007
100000007
取模
【思路】
首先
m<=n
m
<=
n
所以
n!
n
!
是
m!
m
!
的整数倍,而且 一个数的所有素因子都大于m 等价于 这个数和m!互素 ,而且根据gcd的性质,对于
k>m!,k
k
>
m
!
,
k
与
m!
m
!
互素等价于
k modm!
k
m
o
d
m
!
和
m!
m
!
互素. 这样一来,只要求出“不超过
m!
m
!
且和
m!
m
!
互素的数的个数” 再乘以
n!m!
n
!
m
!
即可,关键就在于求出
phi(m!)
p
h
i
(
m
!
)
设
phifac(n)=phi(n!)
p
h
i
f
a
c
(
n
)
=
p
h
i
(
n
!
)
根据欧拉函数公式
如果 n n 不是素数,那么 和 (n−1)! ( n − 1 ) ! 的素因子集合完全相同,
如果 n n 是素数,还会多一项 约分得
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=100000007;
const int maxn=10000005;
int fac[maxn];
int invfac[maxn];
int phifac[maxn];
bool notprime[maxn];
int n,m;
void gcd(ll a,ll b,ll &d,ll& x,ll& y){
if (0==b){ d=a;x=1;y=0; }
else { gcd(b,a%b,d,y,x);y-=x*(a/b); }
}
ll inv(ll a,ll p){
ll d,x,y;
gcd(a,p,d,x,y);
return d==1?(x+p)%p:-1;
}
void init(){
notprime[0]=notprime[1]=true;
for(int i=2;i<maxn;++i){
if(!notprime[i]) for(int j=i*2;j<maxn;j+=i) notprime[j]=true;
}
fac[0]=fac[1]=1;
for(int i=2;i<maxn;++i) fac[i]=(ll)fac[i-1]*(ll)i%mod;
for(int i=0;i<maxn;++i) invfac[i]=inv(fac[i],mod);
phifac[1]=phifac[2]=1;
for(int i=3;i<maxn;++i){
phifac[i]=(ll)phifac[i-1]*(ll)(notprime[i]?i:i-1)%mod;
}
}
int main(){
init();
while(scanf("%d%d",&n,&m)==2){
if(0==n && 0==m) break;
int ans=phifac[m];
ans=(ll)ans*(ll)fac[n]%mod;
ans=(ll)ans*(ll)invfac[m]%mod;
printf("%d\n",(ans-1+mod)%mod);
}
return 0;
}