码迷,mamicode.com
首页 > 其他好文 > 详细

[SDOI2008]沙拉公主的困惑

时间:2019-06-18 20:02:26      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:cst   sum   void   can   循环   while   pac   a+b   play   

\(1\sim n!\)中与\(m!\)互质的数的个数。\(m\leq n\leq 10^7\).

显然\(m!|n!\)。根据GCD的性质,\((a,b)=(a+b,b)\),则\((a,m!)=(a+m!,m!)\)。于是每\(m!\)分一组,易得
\[ ans=\sum_{i=1}^{n!}[(i,m!)=1]\=\frac{n!}{m!}\varphi(m!)=n!\prod\frac{p_i-1}{p_i},p_i\leq m \]
然后。就被开心地卡常了。

逆元要写递推的,而且还要避免多次取模。见代码。

循环尽量别合并。

#include<cstdio>
using namespace std;
const int N=1e7+5;

int t,r,n,m;
int vis[N],p[N/10],lp;
void sieve(int k){
    vis[0]=vis[1]=1;
    for(int i=2;i<=k;i++){
        if(!vis[i])p[++lp]=i;
        for(int j=1;j<=lp;j++){
            if(i*p[j]>k)break;
            vis[i*p[j]]=1;
            if(i%p[j]==0)break;
        }
    }
}
int fac[N],inv[N],fp[N];//fac phi
int main(){
    scanf("%d%d",&t,&r);

    sieve(1e7);
    fac[0]=1;
    for(int i=1;i<=10000000;i++)fac[i]=1ll*i*fac[i-1]%r;
    inv[1]=1;
    for(int i=2;i<=10000000;i++)inv[i]=(1ll*(r-r/i)*inv[r%i]%r);
    fp[1]=1;
    for(int i=2;i<=10000000;i++){
        fp[i]=fp[i-1];
        if(vis[i]==0)fp[i]=1ll*fp[i]*(i-1)%r*inv[i]%r;
    }

    while(t--){
        scanf("%d%d",&n,&m);
        printf("%lld\n",1ll*fac[n]*fp[m]%r);
    }
    return 0;
}

[SDOI2008]沙拉公主的困惑

标签:cst   sum   void   can   循环   while   pac   a+b   play   

原文地址:https://www.cnblogs.com/sshwy/p/11047129.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!