Solution:
题意即求1~N!中与M!互质的数的个数。
由于,所以有
,又因为有
。
可推得
后面的纯阶乘预处理较简单,考虑前面括号中的预处理,可推出:
当i是质数时,有
当i是合数时,有
所以只需再预处理出逆元,就可以在O(n)的时间里预处理出需要的值,每个询问O(1)回答即可。
Code:
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rep2(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
template <typename T> inline void read(T &x) {
x = 0; T f = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
x *= f;
}
template <typename T> inline void chkmax(T &x , T y) {x = x > y ? x : y ; }
template <typename T> inline void chkmin(T &x , T y) {x = x < y ? x : y ; }
int T,R;
int powe[10000010];int fin[10000010];int inv[10000010];
int prime[10000010];int f[10000010];int len=0;
inline int poww(int n,int m){
int tmp=m;int temp=n;int ret=1;
while(tmp){
if(tmp&1)ret=(1ll*ret*temp)%R;
temp=(1ll*temp*temp)%R;
tmp>>=1;
}
return ret;
}
inline void Pretreatment(){
powe[0]=powe[1]=1;
rep(i,2,10000000)powe[i]=(1ll*powe[i-1]*i)%R;
rep(i,2,10000000){
if(!f[i]){prime[++len]=i;f[i]=i;}
rep(j,1,len){
if(prime[j]*i>10000000)break;
f[prime[j]*i]=prime[j];
if(i%prime[j]==0)break;
}
}
inv[1]=1;
rep(i,2,10000000)inv[i]=(1ll*(R-R/i)*inv[R%i])%R;
fin[1]=1;
rep(i,2,10000000){
if(f[i]==i){
fin[i]=(1ll*fin[i-1]*(i-1))%R;fin[i]=(1ll*fin[i]*inv[i])%R;
}else{fin[i]=fin[i-1];}
}
return;
}
int main(){
read(T);read(R);
Pretreatment();
while(T--){
int n,m;read(n);read(m);
int ans=(1ll*powe[n]*fin[m])%R;
printf("%d\n",ans);
}
return 0;
}