http://www.cnblogs.com/BLADEVIL/p/3490321.html
http://www.cnblogs.com/zyfzyf/p/3997986.html
翻了翻题解,这两个合起来比较明白……
题意:求1~n!中与m!互质的数的数量(mod R)。
∵由欧几里得算法得gcd(a,b)=gcd(b,a%b)
∴gcd(a+b,b)=gcd(b,(a+b)%b)=gcd(b,a) 即 gcd(a,b)=gcd(a+b,b)
推广:gcd(a,b)=gcd(a+k*b,b)
∴若a与b互质,则a+k*b也与b互质
令n=5,m=4,则n!=120,m!=24
符合题意的数有以下:
5 29 53 77 101
7 31 55 79 103
11 35 59 83 107
13 37 61 85 109
17 41 65 89 113
19 43 67 91 115
23 47 71 95 119
∴若x(x<n!)与m!互质,则x+m!*k也和m!互质,根据我们刚才推出的性质,仔细观察,发现 x 在 mod m!的剩余系中恰好有n!/m!个数符合题意。
∴观察上表的第一列,我们只需考虑小于m!的数中与n!互质的数。
∴这样的数恰好有φ(m!)个
∴答案为φ(m!)*(n!/m!)
但是这样仍然超出了我们能承受的时间复杂度。
∴ans=φ(m!)*(n!/m!)
=m!*((p1-1)/p1)+((p2-1)/p2)+......+((pk-1)/pk)*n!/m! (p1......pk为m!的质因子,根据阶乘的定义,易证,m!的质因子恰好为<=m的所有质数)
=((p1-1)/p1)+((p2-1)/p2)+......+((pk-1)/pk)*n!
∴我们递推预处理出((p1-1)/p1)+((p2-1)/p2)+......+((pk-1)/pk)和n!即可O(1)地回答每个询问。
在预处理连续乘积的时候,我们要用到快速幂求乘法逆元。
综上,要预处理的是:
①maxm以内的素数
②maxm以内的素数的逆元
③1!~maxn!
④maxm以内的素数的((p1-1)/p1)+((p2-1)/p2)+......+((pk-1)/pk)
1 #include2 #include 3 #include 4 using namespace std; 5 typedef long long ll; 6 ll MOD; 7 int T,n[10001],m[10001],maxn,maxm,Ni[10000001],Fac[10000001],Muls[10000001]; 8 bool unPrime[10000001]; 9 void Shai_Prime()10 {11 unPrime[1]=true;12 for(ll i=2;i<=maxm;i++)13 for(ll j=i*i;j<=maxm;j+=i) unPrime[j]=true;14 }15 ll pow_mod(ll a,ll p,ll MOD)16 {17 if(!p) return 1;18 ll ans=pow_mod(a,p>>1,MOD);19 ans=ans*ans%MOD;20 if((p&1)==1) ans=ans*a%MOD;21 return ans;22 }23 void Init_Ni()24 {25 for(int i=1;i<=maxm;i++)26 if(!unPrime[i])27 Ni[i]=(int)pow_mod(i,MOD-2,MOD);28 }29 void Init_Fac()30 {31 Fac[1]=1;32 for(int i=2;i<=maxn;i++) Fac[i]=(int)((ll)Fac[i-1]*(ll)i%MOD);33 }34 void Init_Muls()35 {36 ll res=1;37 for(int i=1;i<=maxm;i++)38 {39 if(!unPrime[i]) res=((res*(ll)(i-1))%MOD)*(ll)Ni[i]%MOD;40 Muls[i]=res;41 }42 }43 int main()44 {45 scanf("%d",&T); cin>>MOD;46 for(int i=1;i<=T;i++)47 {48 scanf("%d%d",&n[i],&m[i]);49 maxn=max(n[i],maxn);50 maxm=max(m[i],maxm);51 }52 Shai_Prime(); Init_Ni(); Init_Fac(); Init_Muls();53 for(int i=1;i<=T;i++)54 printf("%d\n",(int)((ll)Muls[m[i]]*(ll)Fac[n[i]]%MOD));55 return 0;56 }