题目描述
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为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
n>m,n!是m!的倍数
gcd(x,m!)=gcd(x-k*m!,m!)
所以只需要求出1到m!中和m!互质的数的个数,再乘以n!/m!;

o(1e7)处理,o1输出询问
1 #include<cstdio>
2 #include<iostream>
3 #include<algorithm>
4 #include<cstring>
5 #include<queue>
6 #include<cmath>
7 #define ll long long
8 #define N 10000050
9 using namespace std;
10 ll jc[N];
11 int ny[N],T,Q,M,ans[N],tot;
12 ll r;
13 int v[N],pri[10000050];
14 void init(ll n){
15 v[1]=1;
16 jc[0]=jc[1]=1;ny[0]=ny[1]=1,ans[0]=ans[1]=1;
17 for(int i=2;i<=n;i++){
18 jc[i]=(ll)(jc[i-1]*i)%r;
19 ny[i]=(ll)(r-r/i)*ny[r%i]%r;
20 if(!v[i]){
21 pri[++tot]=i;
22 }
23 for(int j=1;j<=tot&&i*pri[j]<=n;j++){
24 v[i*pri[j]]=1;
25 if(i%pri[j]==0)break ;
26 }
27 }
28 for(int i=2;i<=n;i++){
29 ans[i]=ans[i-1];
30 if(!v[i])ans[i]=(ll)ans[i]%r*(i-1)%r*ny[i]%r;
31 }
32 }
33 int main(){
34 scanf("%d%lld",&T,&r);
35 init(10000000);
36 while(T--){
37 scanf("%d%d",&Q,&M);
38 printf("%lld
",(ll)jc[Q]%r*ans[M]%r);
39 }
40 return 0;
41 }