Solution
又是一道数论题耶!本来感觉又要反演了,其实不用的。
多组数据,每次给定N,M的值,求。
可以想到,如果gcd(i,M!)=1,那么gcd(i+k*(M!),M!)=1.
所以询问就可以转化成
即φ(M!)*(N!/M!).
前者展开,即M!* (p-1)/p (p|M! && p is prime)
因为p为质数,所以p|M!即p|M。所以只要预处理出阶乘和(p-1)/p的乘积即可。
这样的话这道题就可以过啦~
再附上线性求逆元的证明吧。
inv[i]=(mod-mod/i)*inv[mod % i];
Proof
令x=mod/i,y=mod % i
则xi+y=0(%mod)
-xi=y(%mod)
同除以i*y得,-x*inv[y]=inv[i](%mod)
所以inv[i]=(mod-mod/i)*inv[mod % i]。
证毕!
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 10000000+1000
using namespace std;
int T,mod,tot,vis[N],prime[N],fac[N],inv[N],mul[N];
long long ans;
int main()
{
scanf("%d%d",&T,&mod);
for(int i=2;i<=N;i++){
if(!vis[i]) prime[++tot]=i;
for(int j=1;j<=tot && i*prime[j]<=N;j++){
vis[i*prime[j]]=1;
if(i % prime[j]==0) break;
}
}
fac[0]=1;
for(int i=1;i<=N;i++) fac[i]=(long long)fac[i-1]*i % mod;
inv[0]=inv[1]=1;
for(int i=2;i<=N;i++) inv[i]=(long long)(mod-mod/i)*inv[mod % i] % mod;
mul[1]=1;
for(int i=2;i<=N;i++){
mul[i]=mul[i-1];
if(!vis[i]) mul[i]=(long long)mul[i]*(i-1) % mod * inv[i] % mod;
}
while(T--){
int n,m;
scanf("%d%d",&n,&m);
ans=(long long)fac[n]*mul[m] % mod;
printf("%lld\n",ans);
}
return 0;
}