题目:
题意:
求 1 — n ! 1—n! 1—n!中有多少个数与 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}
pi∗pjn!
整理一下我们刚刚提到的式子,得到我们本题的公式:
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!+pi∗pjn!
将
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!∗(1−pi1−pj1+pi∗pj1)
对后面的式子用下乘法公式得到:
n
!
∗
(
1
−
1
p
i
)
∗
(
1
−
1
p
j
)
n!*(1-\frac{1}{p_i})*(1-\frac{1}{p_j})
n!∗(1−pi1)∗(1−pj1)
最后我们枚举每个素数,得到最后最后的公式:
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=1∏kpi−1÷i=1∏kpi
因为有模数,所以我们根据费马小定理求出最后一项的逆元就可以边乘边除了
这里给出加上求逆元的公式:
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=1∏kpi−1∗(i=1∏kpi)m−2
代码:
#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;
}