BZOJ2186 SDOI2008沙拉公主的困惑(数论)

  由于n!是m!的倍数,而对于每个与m!互质且小于m!的数x,x+m!、x+2*m!……也与其互质,所以答案即为(n!/m!)*φ(m!)。

  φ(m!)=m!*∏(1-1/pi)。其中的pi即为1~m中所有质数。那么这个前缀积就可以预处理了。

  当n、m大于p的时候是可能有问题的,数据里没有就懒得讨论了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 10000010
int T,P,prime[N],exphi[N],cnt=0;
int fac[N],inv[N],inv2[N];
bool flag[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj2186.in","r",stdin);
    freopen("bzoj2186.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    T=read(),P=read();
    fac[0]=1;for (int i=1;i<min(P,N-9);i++) fac[i]=1ll*fac[i-1]*i%P;
    inv[1]=1;for (int i=2;i<min(P,N-9);i++) inv[i]=(P-1ll*(P/i)*inv[P%i]%P)%P;
    inv2[1]=1;for (int i=2;i<min(P,N-9);i++) inv2[i]=1ll*inv2[i-1]*inv[i]%P;
    flag[1]=1;
    for (int i=2;i<min(P,N-9);i++)
    {
        if (!flag[i]) prime[++cnt]=i;
        for (int j=1;j<=cnt&&prime[j]*i<=N-10;j++)
        {
            flag[prime[j]*i]=1;
            if (i%prime[j]==0) break;
        }
    }
    exphi[1]=1;
    for (int i=2;i<min(P,N-9);i++)
    if (!flag[i]) exphi[i]=1ll*exphi[i-1]*(P+1-inv[i])%P;
    else exphi[i]=exphi[i-1];
    for (int i=1;i<min(P,N-9);i++)
    exphi[i]=1ll*exphi[i]*fac[i]%P;
    while (T--)
    {
        int n=read(),m=read();
        printf("%d\n",1ll*fac[n]*inv2[m]%P*exphi[m]%P);
    }
    return 0;
}

 

posted @ 2018-09-16 16:14  Gloid  阅读(114)  评论(0编辑  收藏  举报