bzoj2186: [Sdoi2008]沙拉公主的困惑 逆元

传送门

题意:求1-n!中与m!互质的数的个数,其中m小于n。

思路:由于m小于n,所以n!一定是m!的倍数,小于m!与m!互质的数的个数为phi(m!),所以1-n!中与m!互质的数的个数为n!/m!*phi(m!)=n!/m!*m!*(1-1/p1)*(1-1/p2)*...(1-1/pk) =n!(1-1/p1)*(1-1/p2)*...(1-1/pk)其中p1-pk是m!的素因子,其实也就是小于m的所有素数,最后结果再对一个素数取余。

这个题时间卡的确实很紧,在求逆元的时候用的是o(p)复杂度来求:

void init()
{
    inv[0]=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/p1)*(1-1/p2)*...(1-1/pk)时先预处理,否则也是超时

完整代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e7+5;
bool prime[maxn];
int cnt;
int mod;
ll inv[maxn];
ll jc[maxn];
ll res[maxn];
void isprime()
{
    prime[0]=false;
    prime[1]=false;
    prime[2]=true;
    for(int i=3;i<maxn;i+=2)
    {
        prime[i]=true;
        prime[i+1]=false;
    }
    for(int i=3;i<=sqrt((double)maxn);i+=2)
        if(prime[i])
            for(int j=i+i;j<maxn;j+=i)
                prime[j]=false;
}
void init()
{
    inv[0]=inv[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(i>=mod) break;
        inv[i]=((mod-mod/i)*inv[mod%i])%mod;
    }
}
void factorial()
{
    jc[0]=jc[1]=1;
    for(int i=2;i<maxn;i++)
    {
        jc[i]=jc[i-1]*i%mod;
    }
}
int main()
{
    int t;
    scanf("%d%d",&t,&mod);
    isprime();
    init();
    factorial();
 
    res[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(prime[i])
        {
            res[i]=res[i-1]*(i-1)%mod;
            res[i]=res[i]*inv[i%mod]%mod;
        }
        else
            res[i]=res[i-1];
    }
 
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        ll ans=jc[n]*res[m]%mod;
        printf("%lld\n",ans);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值