P2155 [SDOI2008] 沙拉公主的困惑(线性筛,逆元)
题解
我们知道
g
c
d
(
m
!
+
k
,
m
!
)
=
g
c
d
(
k
,
m
!
)
gcd(m!+k,m!)=gcd(k,m!)
gcd(m!+k,m!)=gcd(k,m!)
若
k
>
m
!
k>m!
k>m! 不妨令
k
=
m
!
+
c
k=m!+c
k=m!+c
于是
g
c
d
(
k
,
m
!
)
=
g
c
d
(
c
,
m
!
)
gcd(k,m!)=gcd(c,m!)
gcd(k,m!)=gcd(c,m!)
我们目标求
1
−
n
!
1-n!
1−n!中
g
c
d
(
i
,
m
!
)
=
=
1
gcd(i,m!)==1
gcd(i,m!)==1的个数
可以将
n
!
n!
n!分成
n
!
/
m
!
n!/m!
n!/m!份
每一份为
m
!
m!
m! 其中与
m
!
m!
m!互质的数的个数为phi(m!)
当m为质数时
p
h
i
(
m
!
)
=
p
h
i
(
(
m
−
1
)
!
)
∗
(
m
−
1
)
phi(m!)=phi((m-1)!)*(m-1)
phi(m!)=phi((m−1)!)∗(m−1)
当m不为质数时
p
h
i
(
m
!
)
=
p
h
i
(
(
m
−
1
)
!
)
∗
m
phi(m!)=phi((m-1)!)*m
phi(m!)=phi((m−1)!)∗m
所以答案为
n
!
m
!
p
h
i
(
m
!
)
\frac{n!}{m!phi(m!)}
m!phi(m!)n!
注意本题又模数与除数非互质的情况,也就是
r
∣
m
!
r|m!
r∣m!,此时重新处理阶乘即可
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
int prime[N],phi[N],cnt;
bool vis[N];
int fac[N];
int x,y;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int res=exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
return res;
}
void init(int n,int mod)
{
phi[1]=1;
fac[0]=fac[1]=1;
for(int i=2;i<=n;i++)
{
fac[i]=fac[i-1]*i%mod;
if(!vis[i]) prime[++cnt]=i,phi[i]=phi[i-1]*(i-1)%mod;
else phi[i]=phi[i-1]*i%mod;
for(int j=1;prime[j]*i<=n;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
int qpow(int a,int n,int mod)
{
int res=1;
while(n)
{
if(n&1) res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
signed main()
{
int t,mod;
cin>>t>>mod;
init(N-4,mod);
while(t--)
{
int n,m;
cin>>n>>m;
if(m%mod) cout<<fac[n]*phi[m]%mod*qpow(fac[m],mod-2,mod)%mod<<endl;
else
{
int tmp=1;
for(int i=m+1;i<=n;i++) (tmp*=i)%=mod;
cout<<tmp*phi[m]%mod<<endl;
}
}
return 0;
}