来自FallDream的博客,未经允许,请勿转载,谢谢。
题意:T组数据,每次求[1,n!]里有多少个与m!互质的数。 T<=10000 n,m<=10^7
一开始想着乱容斥啥的 根本不可做...但是实际上没那么复杂。
考虑把[1,n!]按照取余m!的不同分成m!组,发现要么全都互质,要么全都不互质,所以我们只要求[1,m!]里跟m!互质的数就好了,也就是求$varphi(m!)$
那么这样就很简单了,根据欧拉函数的一套理论(#滑稽),我们先筛出质数,然后$varphi(m!)=m!*prod{frac{i-1}{i}}$,其中$1leqslant ileqslant m$且i是质数。
答案就是$frac{n!}{m!}varphi(m!)$
实现上还要线性求个逆元,这都很简单啦。
然后考虑R<=m的情况,貌似出题人没有考虑到或者没有写出来,虽然不判断都能过,但是直接这么算是不行的。
发现p在筛的时候会被除掉,所以在算阶乘的时候忽略它,然后在算的时候也不算它的逆元,可能就行了?
貌似好麻烦,懒得实现了。
#include<iostream> #include<cstdio> #define MN 10000000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int s[MN+5],T,mod,f[MN+5],num=0,inv[MN+5],p[MN+5]; bool b[MN+5]; int main() { T=read();mod=read(); f[1]=1,p[0]=p[1]=inv[0]=inv[1]=1; for(register int i=2;i<=MN;++i) { if(!b[i]) s[++num]=i; for(int j=1;s[j]*i<=MN;++j) { b[s[j]*i]=1; if(i%s[j]==0) break; } } for(register int i=2;i<=MN;++i) p[i]=1LL*p[i-1]*i%mod,inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; for(register int i=2;i<=MN;++i) f[i]=(b[i]?f[i-1]:(1LL*f[i-1]*(i-1)%mod*inv[i]%mod)); for(register int i=1;i<=T;++i) { int n=read(),m=read(); printf("%d ",1LL*p[n]*f[m]%mod); } return 0; }