洛咕 P2155 [SDOI2008]沙拉公主的困惑

洛咕 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!\Pi\frac{p-1}{p}=n\times \Pi\frac{p-1}{p}\)

就是\(m!\)有哪些质因数,显然就是1-m所有数质因数的并,也就是\(\Pi_{i\leq m \text{ 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\n",1ll*p[n]*s[m]%R);
    }
    return 0;
}
posted @ 2018-10-17 22:08  菜狗xzz  阅读(163)  评论(0编辑  收藏  举报