BZOJ-2186 [Sdoi2008]沙拉公主的困惑(欧拉函数)
题目描述
求 \(1\) ~ \(n!\) 中与 \(m!\) 互质的数的个数,答案对 \(mod\) 取模。
数据范围:\(T\leq 10^4,1\leq n,m\leq 10^7,mod\leq 10^9+10\),\(mod\) 是一个质数。
分析
引理:若 \(\gcd(x,y)=1\),则 \(\gcd(x,y+kx)=1\)(可以用更相减损术证明)。
把 \([1,n!]\) 分成 \(\frac{n!}{m!}\) 段:\([1,m!],[m!+1,2m!],\cdots,[km!+1,m!]\),由于 \(\gcd(x,m!)=1\),则 \(\gcd(x+km!,m!)\),所以每一段中与 \(m!\) 互质的数都是相同的,有 \(\varphi(m!)\) 个,因此答案为 \(\frac{n!}{m!}\varphi(m!)\),即 \(n!\displaystyle\prod_{i=1}^{k}\frac{1-p_i}{p_i}\),筛法预处理质数,阶乘和 \(\varphi\)。
由于 \(mod\) 未必大于 \(n\),因此 \(1\) ~ \(n\) 中可能有 \(mod\) 的倍数,因此把每个数字都分解成 \(a\times mod^{b}\) 的形式,用两个数组分开记录,在预处理阶乘和欧拉函数时,\(a\) 相乘,\(b\) 相加,最后判断 \(fac2[n]+phi2[m]-fac2[m]\) 是否等于 \(0\) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int prime[N+10],cnt;
bool vis[N+10];
int fac1[N+10],fac2[N+10],phi1[N+10],phi2[N+10];
int n,m,mod;
void init()
{
vis[1]=1;
for(int i=2;i<=N;i++)
{
if(!vis[i])
prime[++cnt]=i;
for(int j=1;i*prime[j]<=N&&j<=cnt;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
fac1[0]=phi1[0]=1;
fac2[0]=phi2[0]=0;
for(int i=1;i<=N;i++)
{
int a=i,b=0;
while(a%mod==0)
{
a=a/mod;
b++;
}
fac1[i]=1ll*fac1[i-1]*a%mod;
fac2[i]=fac2[i-1]+b;
if(vis[i]==1)
a=i;
else
a=i-1;
b=0;
while(a%mod==0)
{
a=a/mod;
b++;
}
phi1[i]=1ll*phi1[i-1]*a%mod;
phi2[i]=phi2[i-1]+b;
}
}
long long quick_pow(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
int T;
cin>>T>>mod;
init();
while(T--)
{
scanf("%d %d",&n,&m);
long long ans=1ll*fac1[n]*phi1[m]%mod*quick_pow(fac1[m],mod-2)%mod;
if(fac2[n]+phi2[m]-fac2[m]!=0)
ans=0;
printf("%lld\n",ans);
}
return 0;
}
posted on 2020-11-29 12:51 DestinHistoire 阅读(58) 评论(0) 收藏 举报