常规数论题,利用欧拉函数的相关性质。
题求$[1,N!]$中与$M!$互质的数的个数,且$M \leq N$。然后根据欧拉函数的相关性质很容易得出这道题的答案为$\frac{\phi (M!) \times N!} {M!}$。欧拉函数并不是完全积性函数,所以$M!$的欧拉函数值并不能很容易的求出来。但是根据欧拉函数的式子,可以发现$\phi (M!)$的值其实也可以预处理出来,即$\phi(M!)=M! \prod\limits ^{P_i \in [2,M]} (1-\frac{1}{P_i})$。然后根据乘法逆元就可以预处理出全部的答案。
//BZOJ 2186 //by Cydiater //2016.10.9 #include <iostream> #include <cstdlib> #include <cstdio> #include <queue> #include <map> #include <ctime> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <iomanip> using namespace std; #define ll long long #define up(i,j,n) for(ll i=j;i<=n;i++) #define down(i,j,n) for(ll i=j;i>=n;i--) const ll MAXN=1e7+5; const ll LIM=1e7; const ll oo=1LL<<40; inline ll read(){ char ch=getchar();ll x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ll N,M,T,mod,prime[MAXN],cnt=0,ans[MAXN],fac[MAXN]; bool vis[MAXN]; namespace solution{ void exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){x=1;y=0;return;} exgcd(b,a%b,x,y); ll t=x;x=y;y=t-a/b*y; } ll inv(ll num){ ll a=num,b=mod,x,y; exgcd(a,b,x,y); while(x<0)x+=b; return x; } void pret(){ fac[1]=1; memset(vis,0,sizeof(vis)); up(i,2,LIM){ fac[i]=fac[i-1]*i%mod; if(!vis[i])prime[++cnt]=i; up(j,1,cnt){ if(prime[j]*i>LIM)break; vis[i*prime[j]]=1; if(i%prime[j]==0)break; } } ans[1]=1; up(i,2,LIM){ ans[i]=ans[i-1]; if(!vis[i])ans[i]=ans[i]*(i-1)%mod*inv(i)%mod; } } } int main(){ freopen("input.in","r",stdin); using namespace solution; T=read();mod=read(); pret(); while(T--){ N=read();M=read(); printf("%lld\n",ans[M]*fac[N]%mod); } return 0; }