0%

「2018夏令营提高组」互质

题目链接

题意

1n!1-n! 的数中与 m!m! 互质的数的个数 (mn)(m\leq n),对质数 RR 取模。

n,m107,R109+10n,m\leq10^7,R\leq10^9+10

思路

因为 mnm\leq n,所以 m!n!m!\mid n!

x,m!x,m! 互质,则 (x+km!),m! (kN)(x+k\cdot m!),m!\ (k\in\mathbb N^*) 互质。

每找到一个与 mm 互质的数 x(x<m!)x(x<m!),我们就在 n!n! 范围内找到了 n!m!\frac{n!}{m!} 个与 mm 互质的数。

答案即为 n!m!φ(m!)\frac{n!}{m!}\cdot\varphi(m!),将其展开得:

将其展开得:

n!m!φ(m!)=n!m!m!(11pri1)(11pri2)(11prik)=n!i=1priimprii1prii\begin{aligned} \frac{n!}{m!}\cdot\varphi(m!)&=\frac{n!}{m!}\cdot m!\cdot(1-\frac1{pri_1})(1-\frac1{pri_2})\cdots(1-\frac1{pri_k})\\ &=n!\cdot\prod_{i=1}^{pri_i\leq m}\frac{pri_i-1}{pri_i} \end{aligned}

其中 pri1prikpri_1-pri_km!m! 的质因数,恰好为小于等于 mm 的质数。

实现

预处理出质数,阶乘。

线性处理出 1m1-m 的逆元。

即可 O(1)O(1) 回答每次询问。

注意:当 nRn\geq R 时,n!0(modR)n!\equiv0\pmod R

考虑答案中含有的质因数 RR 数目,若 n!n! 中含有的 RR 数目大于 11,或 n!n! 含有 RR 数目为 11m<Rm<R,结果为 00

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<cstdio>
using namespace std;
const int maxn=10000000;
int t,mod,n,m;
long long fac[maxn+1],inv[maxn+1],res[maxn+1];
bool pri[maxn+1];
int main()
{
freopen("prime.in","r",stdin);
freopen("prime.out","w",stdout);
pri[2]=1;
for(int i=3;i<maxn;i+=2) {
pri[i]=1,pri[i+1]=0;
}
for(int i=3;i*i<=maxn;++i) {
if(pri[i]) {
for(int j=(i<<1)+i;j<=maxn;j+=i<<1) {
pri[j]=0;
}
}
}
scanf("%d%d",&t,&mod);
fac[0]=1;
for(int i=1;i<=maxn;++i) {
fac[i]=i%mod?fac[i-1]*i%mod:fac[i-1];
}
inv[0]=inv[1]=1;
for(int i=2;(i<=maxn)&&(i<mod);++i) {
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
res[1]=1;
for(int i=2;i<=maxn;++i) {
res[i]=pri[i]?(res[i-1]*(i-1)%mod*inv[i%mod]%mod):res[i-1];
}
while(t--) {
scanf("%d%d",&n,&m);
printf("%lld\n",(n>=mod<<1)||((n>=mod)&&(m<mod))?0ll:fac[n]*res[m]%mod);
}
return 0;
}