首先我们看到题目要求的是1~N!内有M!互质的个数
N!>M!,而我们是知道在M!以内与M!互质的数的个数,即phi(M!)
但是M!~N!内与M!互质的数有多少个呢?
对于每个互质的数,如果我们给他都加上M!,那一定也和M!互质
所以1~N!之间与M!互质的数为phi(M!)*(N!/M!)
由于M!很大,不能有以前的方法计算,我们可以考虑用公式计算
phi(m)=m*(p1-1)/p1*(p2-1)/p2……*(pk-1)/pk pk为m的素因数
因为m!所包含的素因数只可能在1~m内,这是比较容易计算出来的
简化可得ans=N!*(p1-1)/p1*(p2-1)/p2……*(pk-1)/pk
由于这道题又牵扯到了除法取模,所以又要用到扩展欧几里得
然后这道题是坑爹的多测,我们要预处理素数表,阶乘表等等,具体见程序
1 var a,b,d:array[0..10000000] of int64; 2 x,y:array[0..10010] of longint; 3 v:array[0..10000000] of boolean; 4 prime:array[0..700010] of longint; 5 tot,j,i,t,p,n,m:longint; 6 r,k,ans,s:int64; 7 8 procedure exgcd(a,b:int64); 9 var z:int64; 10 begin 11 if b=0 then 12 begin 13 r:=1; 14 k:=0; 15 end 16 else begin 17 exgcd(b,a mod b); 18 z:=r; 19 r:=k; 20 k:=z-(a div b)*k; 21 end; 22 end; 23 24 begin 25 readln(t,p); 26 for i:=1 to t do 27 begin 28 readln(x[i],y[i]); 29 if x[i]>m then m:=x[i]; 30 end; 31 for i:=2 to m do //筛素数 32 begin 33 if not v[i] then 34 begin 35 inc(tot); 36 prime[tot]:=i; 37 end; 38 for j:=1 to tot do 39 begin 40 if i*prime[j]>m then break; 41 v[i*prime[j]]:=true; 42 if i mod prime[j]=0 then break; 43 end; 44 end; 45 d[1]:=1; 46 a[1]:=1; 47 b[1]:=1; 48 for i:=2 to m do 49 begin 50 a[i]:=a[i-1]; 51 b[i]:=b[i-1]; 52 if not v[i] then 53 begin 54 a[i]:=a[i]*int64(i-1) mod p; 55 b[i]:=b[i]*int64(i) mod p; 56 end; 57 d[i]:=d[i-1]*int64(i) mod p; 58 end; 59 for j:=1 to t do 60 begin 61 ans:=d[x[j]]*a[y[j]] mod p; 62 exgcd(b[y[j]],p); 63 r:=(r+p) mod p; 64 writeln(ans*r mod p); 65 end; 66 end.