题解 P2155【[SDOI2008] 沙拉公主的困惑】

· · 题解

题意简述:给定 N,M,R,求 [1,N!] 中与 M! 互质的数的数量。

伟大的欧几里得已经告诉我们该怎么做了。

题目中限定了 M \leq N,那么显然 M! | N!.

常识告诉我们,gcd(a,b)=gcd(a+k\times b,b).然而常识很多时候是假的,所以我们考虑证明这个式子。

设 s=gcd(a,b), 则存在 x,y\in\mathbb{Z}使得 a=x\times s,b=y\times s,gcd(x,y)=1,于是 gcd(a+b\times k,b)=gcd(x\times s+y\times s\times k,y\times s)=gcd(s\times(x+y\times k),s\times y)=s\times gcd(x+y\times k,y).

设 m|(x+y\times k) 且 m|y,所以 m|(y\times k),所以 m|x.即 m|x 且 m|y,又因为 gcd(x,y)=1,所以 gcd(x+y\times k,y)=m=1,所以 gcd(a+b\times k,b)=s\times gcd(x+y\times k,y)=s=gcd(a,b).

这个式子能说明什么呢?我们令 b=M!,显然可以发现:对于 \forall k\in [1,\frac{N!}{M!}],\forall x\in[1,M!] 有 gcd(k*M!+x,M!)=gcd(x,M!).

也就是说,对于 \forall k\in [1,\frac{N!}{M!}], [(k-1)\times M!+1,k\times M!] 中与 M! 互质的数是相等的。

得出这个结论之后就简单了。答案就是 \frac{N!}{M!}\times \phi(M!).

我们知道 $\phi(n)=n\times\Pi_{p|n}(1-\frac{1}{p})$, 设 $phifac_i=\phi(i!)$,我们分两种情况讨论。 $n$ 为素数时,$phifac_i=n\times(1-\frac{1}{n})\times(n-1)!\times\Pi_{p|n!\&p\neq n}(1-\frac{1}{p})=(n-1)\times (n-1)!\times\Pi_{p|(n-1)!}(1-\frac{1}{p})=(n-1)\times phifac_{n-1}$. $n$ 为合数时, $phifac_i=n\times(n-1)!\times\Pi_{p|n!}(1-\frac{1}{p})=n\times phifac_{n-1}$. 这样我们就得到了阶乘的欧拉函数的递推式。 预处理出阶乘和欧拉函数,对于每个询问计算 $M!$ 的逆元即可。 但是题目中没有规定 $R\leq N$ 所以有可能会出现 $R|N!$,预处理阶乘和欧拉函数的时候要记得特判如果 $R|i$ 那么要把 $i$ 中的 $R$ 因子全部除掉再计算。 最后特判一下,如果 $\lfloor \frac{N}{R}\rfloor>\lfloor\frac{M}{R}\rfloor$ (即 $N!$ 中 $R$ 因子更多)则答案为 $0$. ```cpp #include <cstdio> using namespace std; inline int read() { int res=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') {res=res*10+ch-'0'; ch=getchar();} return res*f; } const int MAXN=10000005; int T,r,n,m; int ispr[MAXN]; int pri[MAXN]; int fct[MAXN]; int phi[MAXN]; inline void IsPrImE() { int cnt=0; ispr[0]=ispr[1]=1; for(register int i=2;i<MAXN;++i) { if(!ispr[i]) pri[++cnt]=i; for(register int j=1;j<=cnt;++j) { if(1ll*i*pri[j]>=MAXN) break; ispr[i*pri[j]]=1; if(!i%pri[j]) break; } } } inline long long qpow(int x,int p) { long long res=1; while(p) { if(p&1) res=1ll*res*x%r; p>>=1; x=1ll*x*x%r; } return res; } signed main() { IsPrImE(); T=read(); r=read(); fct[0]=phi[0]=1; for(register int i=1;i<MAXN;++i) { int x=i,k=0; while(x%r==0) x/=r,++k; fct[i]=fct[i-1]*1ll*x%r; x=i-1+ispr[i],k=0; while(x%r==0) x/=r,++k; phi[i]=phi[i-1]*1ll*x%r; } while(T--) { n=read(); m=read(); long long ans=1ll*fct[n]*phi[m]%r*qpow(fct[m],r-2)%r; if(n/r>m/r) ans=0; printf("%lld\n",ans); } return 0; } ```