BZOJ2186 [Sdoi2008]沙拉公主的困惑 数论:递推求逆元

来源:互联网 发布:tmt行业 知乎 编辑:程序博客网 时间:2024/04/25 07:45

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2186


题目大意:求1到n!中与m!互素的数的个数。


分析:我们知道,1到m中与m互素的数的个数是Φ(m)个,如果有m|n,那么我们有:1到n中与m互素的数的个数为n/m*Φ(m)个。这样问题就变为了求n!* ∏(1-1/pi)。


实现代码如下:

#include <cstdio>#include <cstring>#include <bitset>using namespace std;typedef long long ll;const int maxn=10000005;int MOD;//bool prime[maxn];bitset <maxn> prime; //比定义bool类型要省时。换成bool果断TLE了ll fac[maxn]; //阶乘ll inv[maxn]; //逆元ll tmp[maxn]; //∏(1-1/pi)void Init(){    //打素数表    //memset(prime,true,sizeof(prime));    prime.set();    for(int i=2;i<maxn;i++)      if(prime[i])        for(int j=i+i;j<maxn;j+=i)          prime[j]=false;    //打阶乘表    fac[0]=1;    for(int i=1;i<maxn;i++)      fac[i]=fac[i-1]*i%MOD;    //打逆元表    inv[1]=1;    for(int i=2;i<maxn;i++)    {        if(i>=MOD) break;        inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;    }    //计算∏(1-1/pi)%MOD    tmp[1]=1;    for(int i=2;i<maxn;i++)    {        if(prime[i])        {            tmp[i]=tmp[i-1]*(i-1)%MOD;            tmp[i]=tmp[i]*inv[i%MOD]%MOD;        }        else tmp[i]=tmp[i-1];    }}int main(){    int t,n,m;    scanf("%d%d",&t,&MOD);    Init();    while(t--)    {        scanf("%d%d",&n,&m);        printf("%lld\n",fac[n]*tmp[m]%MOD);    }    return 0;}


0 0
原创粉丝点击