洛咕 P2155 [SDOI2008]沙拉公主的困惑
有个结论,就是如果(gcd(a,b)=1),那么(gcd(a+kb,b)=1)。证明比较显然。
所以这个题目要问的(n!)就可以分成(frac{n!}{m!})段,每一段和(m!)互质的数量都相同,那么显然就是(phi(m!))
所以答案是(frac{n!}{m!}phi(m!))
然后怎么求呢,拆开
(frac{n!}{m!}phi(m!)=frac{n!}{m!}m!Pifrac{p-1}{p}=n imes Pifrac{p-1}{p})
就是(m!)有哪些质因数,显然就是1-m所有数质因数的并,也就是(Pi_{ileq m ext{ and i is prime}}frac{i-1}{i})。
这两个都可以直接预处理,就做完了。。
#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int p[10000001],inv[10000001],pr[665000],d[10000001],dd[10000001];
int s[10000001];
bool yes[10000001];
int main(){
#ifndef ONLINE_JUDGE
freopen("1473.in","r",stdin);
freopen("1473.out","w",stdout);
#endif
ll T=gi(),R=gi(),n,m;
for(int i=2;i<=10000000;++i){
if(!yes[i])pr[++pr[0]]=i,d[i]=dd[i]=i;
for(int j=1;1ll*i*pr[j]<=10000000&&j<=pr[0];++j){
yes[i*pr[j]]=1;d[i*pr[j]]=pr[j];
if(i%pr[j]==0){
dd[i*pr[j]]=dd[i];
break;
}
dd[i*pr[j]]=dd[i]*pr[j];
}
}
p[0]=1;for(int i=1;i<=10000000;++i)p[i]=1ll*p[i-1]*i%R;
inv[1]=1;for(int i=2;i<R&&i<=10000000;++i)inv[i]=(R-1ll*(R/i)*inv[R%i]%R)%R;
for(int i=1;i<=pr[0];++i)s[pr[i]]=1ll*(pr[i]-1)*inv[pr[i]]%R;
s[1]=1;
for(int i=2;i<=10000000;++i)
if(s[i]==0)s[i]=s[i-1];
else s[i]=1ll*s[i]*s[i-1]%R;
while(T--){
n=gi(),m=gi();
if(n>R)puts("0");
else printf("%lld
",1ll*p[n]*s[m]%R);
}
return 0;
}