[Sdoi2008](bzoj2186)沙拉公主的困惑

Description

  大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。

Input

第一行为两个整数T,R。R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模后面T行,每行一对整数N,M,见题目描述 m<=n

Output

共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值

数据范围:

对于100%的数据,1 < = N , M < = 10000000

分析

首先很显然,答案等于 n!m!ϕ(m!)

模数是提前给出的,所以可以先预处理出 ϕ(1!)ϕ(2!)ϕ(107!) ,以及1到 107 的阶乘及其的逆元。

预处理phi

首先线性筛出范围内的素数,然后已经求出 ϕ((m1)!) ,现在要求 ϕ(m!) 。根据欧拉函数的性质,如果m为素数,那么 ϕ(m!)=phi((m1)!)(m1) ,否则 ϕ(m!)=ϕ((m1)!)m

预处理阶乘逆元

用扩展欧几里得或快速幂会超时,要先线性求1—— 107 的逆元,然后像阶乘一样乘在一起即可。
线性求逆元方法:

Inv[1]=1;
for (int i=2;i<=nn;i++) Inv[i]=(LL)Inv[mo%i]*(mo-(mo/i))%mo;

然后询问O(1)解决

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int maxn=10000005,N=1e7;

typedef long long LL;

int T,mo,n,m,ans,nn,phi[maxn],tot,pr[maxn],fact[maxn],Inv[maxn],ii[maxn];

bool bz[maxn];

void init()
{
    for (int i=2;i<=nn;i++)
    {
        if (!bz[i]) pr[tot++]=i;
        for (int j=0;j<tot && i*pr[j]<=nn;j++)
        {
            bz[i*pr[j]]=1;
            if (i % pr[j]==0) break;
        }
    }
    Inv[1]=1;
    for (int i=2;i<=nn;i++) Inv[i]=(LL)Inv[mo%i]*(mo-(mo/i))%mo;
    fact[0]=ii[0]=1;
    for (int i=1;i<=nn;i++)
    {
        fact[i]=(LL)fact[i-1]*i%mo;
        ii[i]=(LL)ii[i-1]*Inv[i]%mo;
    }
    phi[1]=1; phi[2]=1;
    for (int i=3;i<=N;i++)
    {
        if (!bz[i]) phi[i]=(LL)phi[i-1]*(i-1)%mo;
        else phi[i]=(LL)phi[i-1]*i%mo;
    }
}

int main()
{
    scanf("%d%d",&T,&mo); nn=min(N,mo);
    init();
    while (T--)
    {
        scanf("%d%d",&n,&m);
        ans=(LL)phi[m]*fact[n]%mo*ii[m]%mo;
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值