咱们在这里介绍一些关于n!的性质。html
在计数问题中,常常须要用到n!。有必要了解n!在mod p下的一些性质。下面咱们假设p是素数,n!=ape(a没法被p整除),并试图求解e和a mod p(把这个东西算出来能够很好的缩小组合数取模的数据)。e是n!中p因子的个数,所以可使用下面的式子进行计算:ide
n/p+n/p2+n/p3+……spa
这个结论很显然,由于n/d和不超过n的能被d整除的个数相等。因为只须要对于pt<=n的t进行计算,所以复杂度O(logp n)。code
接下来计算a mod p。首先计算n!=1*2*……*n的因数中不能被p整除的项的积。假设n=10,p=3则有htm
n!=1*2*4*5*7*8*10*(3*6*9)blog
1*2*4*5*7*8*10≡1*2*1*2*1*2*1(mod p)递归
从这个例子能够看出,不能被p整除的项的积等于(p-1)!(n/p)*(n mod p)!事实上根据威尔逊定理(代码的后面有证实),咱们有(p-1)!≡-1(mod p)。由于除了1和p-1以外的项均可以和各自的逆元相乘获得1。get
而后再处理一下能够被p整除的项就能够了(拿上面的例子来讲就是三、六、9,都除以3以后还剩一、2)。具体的程序仍是能够用递归来实现。io
代码以下:event
1 int fact[MAXN];//fact里面存的是已经处理完毕的阶乘的值 2 int mod_fact(int n,int p,int &e){ 3 e=0; 4 if(n==0)return 1; 5 int res=mod(n/p,p,e); 6 e+=n/p; 7 if(n/p%2==1)return res*(p-fact[n%p])%p;//乘res递归处理是为了处理后面p的倍数 8 return res*fact[n%p]%p; 9 }
如下是威尔逊定理的证实:
首先咱们须要先了解一下缩系:
若整数A1,A2,...,Am模n分别对应0,1,2,...,n-1中全部m个与n互素的天然数,则称集合{A1,A2,...,Am}为模n的一个缩系。
下面咱们来证实下威尔逊定理:
威尔逊定理:当且仅当p为素数时:( p -1 )! ≡ -1 ( mod p)
必要性:若是p不是素数,那么它的正因数必定在1,2,3……(p-1)之中,因此gcd(p, (p-1)!)>1因此p必定是素数。
充分性:
若p是素数,取集合 A={1,2,3,...p -1}; 则A 构成模p乘法的缩系,即任意i∈A ,存在j∈A,使得:( i j ) ≡ 1 ( mod p )那么A中的元素是否是刚好两两配对呢? 不必定,但只需考虑这种状况
x^2 ≡ 1 ( mod p )
解得: x ≡ 1 ( mod p ) 或 x ≡ p-1 (mod p)
其他两两配对;故而( p - 1 )! ≡ 1*( p -1 ) ≡ -1 ( mod p)