求在1到n!范围内,与m!互质的数的数量,由于答案太大,只需计算答案对R取模之后的答案即可,保证R是一个质数 对于30%的数据,n<=10,T<=30 对于60%的数据n<=3000000,T<=10000 对于100%的数据n<=10000000,T<=10000 保证R为质数,m<=n,n < R 题意很简单,,看见n<=10000000就知道要预处理。。 ans=phi(m!)*n!/m! =m!n!/m!(pi-1)/pi(pi是m!的质因数) =n!*(pi-1)/pi 所以这道题的难点就在于怎样预处理1-10000000的素数和逆元。 素数很简单,用欧拉筛法就可以了。 那么逆元呢? 很可惜,,我问遍了很多人,结果只得到下面结论,,,并不知道怎么推的。。 p=na+b, b*b’=1, (p-na)*b’=1, -nab’=1 mod p, n’=-ab’ 用b’推n’ 然后可以得出i’=(p-trunc(p/i))*(p-i*trunc(p/i))’ mod p 很明了的式子呢。。可惜并不会手推,,我觉得能理解就最好不要记模板。。 下面是代码:
const maxn=10000000; var t,r,n,m,cnt,i,j:longint; fac:array[0..10000005]of longint; ine:array[0..10000005]of longint; pri:array[0..500005]of longint; ans:array[0..10000005]of longint; mark:array[0..10000005]of boolean; procedure pre; var i,j:longint; begin fac[1]:=1; for i:=2 to maxn do fac[i]:=int64(fac[i-1])*i mod r; ine[1]:=1; for i:=2 to maxn do begin if(not mark[i])then begin inc(cnt); pri[cnt]:=i; end; j:=1; while (pri[j]*i<=maxn)and(j<=cnt)do begin mark[pri[j]*i]:=true; if (i mod pri[j]=0)then break; inc(j); end; end; for i:=2 to maxn do if i<r then ine[i]:=((r-trunc(r/i))*ine[r-i*trunc(r/i)]mod r); ans[1]:=1; for i:=2 to maxn do begin ans[i]:=ans[i-1]; if(not mark[i])then ans[i]:=int64(ans[i])*(i-1)mod r*ine[i mod r]mod r; end; end; begin read(t,r); pre; while t<>0 do begin read(n,m); writeln(int64(fac[n])*ans[m]mod r); dec(t); end; end.