x的所有素因子都大于M ==> x与M!互质。
若x>M!,那么x与M!互质 ==> x%(M!)与M!互质。
因为M<=N,所以N!是M!的倍数,即M!能整除N!。那么我们只要算出小于M!的数中与M!互素的个数。然后乘以N!/M!就是答案。
如何求M!的欧拉函数呢?用递推的方法。
phi[i]表示i!的欧拉函数。
phi[1]=phi[2]=1;
for(ll i=3;i<=n;i++)
if(vis[i]) phi[i]=phi[i-1]*i%mod;
else phi[i]=phi[i-1]*(i-1)%mod;
如果是i不是素数,那么
phi[i]=phi[i-1]*i%mod;
因为此时i!和(i-1)!的素因子集合完全相同。根据φ(n)=n(1-1/p1)(1-1/p2)...(1-1/pk)。乘一个i就好了。
如果i是素数,那么
phi[i]=phi[i-1]*(i-1)%mod;
根据公式,要乘以i*(1-1/i)=i-1。
最后答案要减1,因为从2开始算。
代码
#include<bits/stdc++.h>
#define maxn 10000010
using namespace std;
typedef long long ll;
const ll mod=100000007;
ll N,M;
bool vis[maxn];
ll phi[maxn];
void init()
{
ll n=10000000;
ll m=sqrt(n+0.5);
for(ll i=2;i<=m;i++)
if(!vis[i])
for(ll j=i*i;j<=n;j+=i)
vis[j]=true;
phi[1]=phi[2]=1;
for(ll i=3;i<=n;i++)
if(vis[i]) phi[i]=phi[i-1]*i%mod;
else phi[i]=phi[i-1]*(i-1)%mod;
}
int main()
{
init();
while(scanf("%lld %lld",&N,&M)==2&&(N+M))
{
ll ans=phi[M];
for(ll i=M+1;i<=N;i++) ans=(ans*i)%mod;
printf("%lld\n",(ans-1+mod)%mod);
}
return 0;
}