题目描述
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
输入格式
第一行为两个整数T,R。R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模 后面T行,每行一对整数N,M,见题目描述 m<=n
输出格式
共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值
输入输出样例
输入 #1
1 11
4 2
输出 #1
1
数据范围:
对于100%的数据,1 < = N , M < = 10000000
解释: g c d ( x , y ) = 1 , 则 g c d ( x + k ∗ y , y ) = 1 gcd(x,y)=1,则gcd(x+k*y,y)=1 gcd(x,y)=1,则gcd(x+k∗y,y)=1这是结论。首先 a n s = ∑ i = 1 N ! [ g c d ( i , M ! ) = = 1 ] ans=\sum_{i=1}^{N!}[gcd(i,M!)==1] ans=∑i=1N![gcd(i,M!)==1]
把它划分为 ( 0 , m ! ] , ( m ! , 2 m ! ] , ( 2 m ! , 3 m ! ] , … , ( k m ! , n ! ] (0,m!],(m!,2m!],(2m!,3m!],…,(km!,n!] (0,m!],(m!,2m!],(2m!,3m!],…,(km!,n!]段,由结论知,每一段数的个数相同,所以
a n s = N ! M ! ∗ ∑ i = 1 M ! [ g c d ( i , M ! ) = = 1 ] = N ! M ! ∗ ϕ ( M ! ) ans=\frac{N!}{M!}*\sum_{i=1}^{M!}[gcd(i,M!)==1]=\frac{N!}{M!}*\phi(M!) ans=M!N!∗∑i=1M![gcd(i,M!)==1]=M!N!∗ϕ(M!),根据 ϕ ( M ! ) \phi(M!) ϕ(M!)的定义,可以线性处理出来,就OK
#include <cstdio>
const int N=1e7+5,M=N/10;
int n,R,tot,p[M],ans[N],fac[N],inv[N];
bool flg[N];
void prework(int n) {
fac[0]=fac[1]=1,inv[0]=inv[1]=1,ans[0]=ans[1]=1;
for(int i=2;i<=n;++i) {
fac[i]=1LL*fac[i-1]*i%R,inv[i]=1LL*(R-R/i)*inv[R%i]%R;
if(!flg[i]) p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=n;++j) {
flg[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
for(int i=2;i<=n;++i) {
ans[i]=ans[i-1];
if(!flg[i]) ans[i]=1LL*ans[i]*(i-1)%R*inv[i]%R;
}
}
int main(){
int T;
scanf("%d%d",&T,&R);
prework(N-5);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",1LL*fac[n]*ans[m]%R);
}
return 0;
}