洛谷 P2155 [SDOI2008]沙拉公主的困惑【欧拉定理】


题目:

传送门


题意:

1 — n ! 1—n! 1n!中有多少个数与 m ! m! m!互质


分析:

p i p_i pi m ! m! m!的素因子
那么我们得到 p i p_i pi必定也是 m m m的素因子
对于 n ! n! n!来说, p i p_i pi的倍数的数量可以表示为 n ! p i \frac{n!}{p_i} pin!
但是我们会发现,如果将所有 p i p_i pi的倍数的数量都减去,那么便会出现重复减的情况,所以我们要用容斥的方法加回来,既加上 n ! p i ∗ p j \frac{n!}{p_i*p_j} pipjn!
整理一下我们刚刚提到的式子,得到我们本题的公式:
n ! − n ! p i − n ! p j + n ! p i ∗ p j n!-\frac{n!}{p_i}-\frac{n!}{p_j}+\frac{n!}{p_i*p_j} n!pin!pjn!+pipjn!
n ! n! n!提出来得到:
n ! ∗ ( 1 − 1 p i − 1 p j + 1 p i ∗ p j ) n!*(1-\frac{1}{p_i}-\frac{1}{p_j}+\frac{1}{p_i*p_j}) n!(1pi1pj1+pipj1)
对后面的式子用下乘法公式得到:
n ! ∗ ( 1 − 1 p i ) ∗ ( 1 − 1 p j ) n!*(1-\frac{1}{p_i})*(1-\frac{1}{p_j}) n!(1pi1)(1pj1)
最后我们枚举每个素数,得到最后最后的公式:
n ! ∗ ∏ i = 1 k p i − 1 ÷ ∏ i = 1 k p i n!*\prod_{i=1}^kp_i-1\div \prod_{i=1}^kp_i n!i=1kpi1÷i=1kpi
因为有模数,所以我们根据费马小定理求出最后一项的逆元就可以边乘边除了
这里给出加上求逆元的公式:
n ! ∗ ∏ i = 1 k p i − 1 ∗ ( ∏ i = 1 k p i ) m − 2 n!*\prod_{i=1}^kp_i-1*(\prod_{i=1}^kp_i)^{m-2} n!i=1kpi1(i=1kpi)m2


代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define LL long long 
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
bool f[10000005];LL p[10000005];
LL k=0;
void ss()
{
    f[0]=f[1]=1;
    for(LL i=2;i<=10000000;i++)
    {
        if(f[i]==0) p[++k]=i;
        for(LL j=1;j<=k&&i*p[j]<=10000000;j++)
          {
            f[i*p[j]]=1;
            if(i%p[j]==0) break;
          }
    }
    return;
}
LL q=read(),LZX=read();
LL ksm(LL x,LL y)
{
	LL s=1;
	while(y)
	{
		if(y&1) (s*=x)%=LZX;
		(x*=x)%=LZX;y>>=1;
	}
	return s%LZX;
}
LL n[10000005],p_1[10000005],p_2[10000005];
int main()
{
    ss();
    n[1]=p_1[1]=p_2[1]=1;
    for(LL i=2;i<=10000000;i++)
    {
    	n[i]=n[i-1]*i%LZX;
    	p_1[i]=p_1[i-1];p_2[i]=p_2[i-1];
    	if(!f[i]) (p_1[i]*=i-1)%=LZX,(p_2[i]*=i)%=LZX;
    }
    while(q--)
    {
    	LL a=read(),b=read();
    	printf("%lld\n",n[a]*p_1[b]%LZX*ksm(p_2[b],LZX-2)%LZX);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值