Description

 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。

Solution

很显然,比m!小的与m!互质的个数,当他们* 2,* 3,*……时,可以倍增出更多的数,与m!互质的数的个数是φ(m!)个。

ans=φ(m!)∗n!m!


ans=m!∗n!m!∗所有质数p|m!(p−1p)的乘积


ans=n!∗所有质数p|m!(p−1p)的乘积


这些线筛就好了。


逆元用快速幂或扩展欧几里得就能过。


不过可以

​​线性求逆元​

Code

#include<iostream> 
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=10000007;
typedef long long ll;
int i,j,k,l,t,n,m;
ll ans1;
int fact[maxn],ni[maxn],ans[maxn];
int p[maxn],cas,mo;
bool bz[maxn];
int main(){
scanf("%d%d",&cas,&mo);
fact[0]=fact[1]=1;ni[1]=1;
fo(i,2,10000000){
fact[i]=(ll)fact[i-1]*i%mo;
ni[i]=(ll)(mo-mo/i)*ni[mo%i]%mo;
if(!bz[i]){
p[++p[0]]=i;
}
fo(j,1,p[0]){
t=p[j]*i;
if(t>10000000)break;
bz[t]=1;
if(!(i%p[j]))break;
}
}
ans[1]=1;
fo(i,2,10000000){
if(bz[i])ans[i]=ans[i-1];
else ans[i]=(ll)ans[i-1]*(i-1)%mo*ni[i]%mo;
}
while(cas--){
scanf("%d%d",&n,&m);
ans1=(ll)fact[n]*ans[m]%mo;
printf("%lld\n",ans1);
}
}