题目链接
题意
求 1−n! 的数中与 m! 互质的数的个数 (m≤n),对质数 R 取模。
n,m≤107,R≤109+10
思路
因为 m≤n,所以 m!∣n!。
若 x,m! 互质,则 (x+k⋅m!),m! (k∈N∗) 互质。
每找到一个与 m 互质的数 x(x<m!),我们就在 n! 范围内找到了 m!n! 个与 m 互质的数。
答案即为 m!n!⋅φ(m!),将其展开得:
将其展开得:
m!n!⋅φ(m!)=m!n!⋅m!⋅(1−pri11)(1−pri21)⋯(1−prik1)=n!⋅i=1∏prii≤mpriiprii−1
其中 pri1−prik 为 m! 的质因数,恰好为小于等于 m 的质数。
实现
预处理出质数,阶乘。
线性处理出 1−m 的逆元。
即可 O(1) 回答每次询问。
注意:当 n≥R 时,n!≡0(modR)。
考虑答案中含有的质因数 R 数目,若 n! 中含有的 R 数目大于 1,或 n! 含有 R 数目为 1 且 m<R,结果为 0。
代码
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; }
|