P2155 [SDOI2008] 沙拉公主的困惑
大家都知道怎样单独求某一个东西的欧拉函数值\(\Psi(m)=m*\prod_{prime_i|m}(\frac{prime-1}{prime})\)
其中右边的东西是用容斥定理搞出来的。那么我们是否也能够用容斥定理处理这个问题?
显然那个\(m\)是需要约去的,并且我们可以快速求出\(\psi(m!)\)那么显然答案就会是
\(\frac{n!}{m!}*\psi(m!)\),这个东西需要逆元,不过那不是问题
(然后被粉兔hack了)
这是为什么呢?
因为我们的逆元是\(m!\)的,如果其中\(m>=r\),应该得到逆元0,也就是无解,输出零
但是如果\(n>=m>=r\)呢? 这时候R因子应该被约掉,所以要特殊处理。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
#define int long long
template<class T>inline void read(T &x)
{
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c))f^=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
}
template<class T>inline void print(T x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar('0'+x%10);
}
int t;
int n;
int r;
int m;
int cnt;
long long prime[10000001];
int maxn=10000005;
int vis[10000005];
int fz[10000005];
void prim(){
for(int i=2;i<=maxn;++i){
if(!vis[i]){
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=maxn;++j){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
break;
}
}
}
}
int qk(int bas,int m,int p){
long long ans=1;
while(m){
if(m&1){
ans=(ans*1ll*bas)%p;
}
bas*=bas;
bas%=p;
m>>=1;
}
return ans;
}
int fac[10000007];
int cop[10000007];
int fm[10000007];
signed main(){
prim();
read(t);read(r);
fac[0]=1;
for(int i=1;i<=maxn;++i){
if(i!=r) fac[i]=fac[i-1]*1ll*i%r;
else fac[i]=fac[i-1];
}
fz[1]=(prime[1]-1)%r;cop[1]=prime[1];
for(int i=2;i<=cnt;++i){
fz[i]=(fz[i-1])*1ll*(prime[i]-1)%r;
cop[i]=prime[i];
}
for(int i=1;i<=cnt;++i){
if(cop[i]!=r) cop[i]=qk(cop[i],r-2,r);
}
for(int i=2;i<=cnt;++i){
if(cop[i]!=r) cop[i]=cop[i]*1ll*cop[i-1]%r;
else cop[i]=cop[i-1];
}
while(t--){
read(n);read(m);
if(m<r&&r<=n){
puts("0");
continue;
}
int pl=upper_bound(prime+1,prime+1+cnt,m)-prime-1;
if(pl<1){
printf("%lld\n",fac[n]);
}else{
printf("%lld\n",fac[n]*1ll*fz[pl]%r*1ll*cop[pl]%r);
}
}
return 0;
}