1. 程式人生 > >洛咕 P2155 [SDOI2008]沙拉公主的困惑

洛咕 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;
}