题意:
给定 n,m(n≥m) ,求 [1,n!] 和 m! 互质的数的个数
解题报告:
分成两部分,第一部分是[1,m!),这部分的答案就是 ϕ(m!)
第二部分是[m!,n!],我们知道有gcd(a,b)==gcd(a+b,b)
所以如果
x
和
所以这部分答案为 ϕ(m!)∗(n!/m!) ,因为 ϕ(x)=m!∗Π(pi−1)/pi,(pi是x的质因子)
可以化为 n!∗Π(pi−1)/pi
然后处理一下素数的逆元直接算就好了,我比较蠢用筛法求出了所有的逆元,于是因为数组太大的问题WA了好久
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define N 10000000
using namespace std;
inline int read(){
int a=0;char f=1,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}
return a*f;
}
int n,m,T,R,cnt,fac[10000005],inv[10000005],prime[500005],f[10000005];
bool mark[10000005];
void Pre(){
fac[1]=1;for(int i=2;i<=N;++i) fac[i]=1ll*fac[i-1]*i%R;
inv[1]=1;
for(int i=2;i<=N;++i){
if(!mark[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=N;++j){
mark[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
for(int i=2;i<=N&&i<R;++i)
inv[i]=(R-1ll*R/i*inv[R%i]%R);
f[1]=1;
for(int i=2;i<=N;++i){
f[i]=f[i-1];
if(!mark[i]) f[i]=1ll*f[i]*(i-1)%R*inv[i%R]%R;
}
}
int main(){
T=read();R=read();
Pre();
while(T--){
n=read(),m=read();
printf("%d\n",1ll*fac[n]*f[m]%R);
}
}