在 p 是素数的情况下,对任意整数 x 都有 xp≡x(modp) 。这个定理被称作费马小定理。其中如果 x 无法被 p 整除,我们有 xp−1≡1(modp) 。利用这条性质,在 p 是素数的情况下,就很容易求出一个数的逆元。把上面的式子变形之后得到 a−1≡ap−2(modp) ,因此可以通过快速幂运算求出逆元。
在不是素数的情况下,我们也有类似的欧拉定理可以使用。假设 m=p1e1p2e2...pnen ,那么 m 的欧拉函数 φ(m) 的定义如下 φ(m)=m×Π(p−1)/p,(Π为连乘符号) 欧拉函数的值等于不超过 m 并且和 n 互素的数的个数。此时对于和加互素的 x ,有 xφ(m)≡1(modm)成立。 在m是素数时,根据定义\varphi (m)=m-1,因此欧拉定理也可以看作是费马小定理的推广。
//求欧拉函数值。O(√n)#define MAX_N 1000inteuler_phi(int n){int res = n;for(int i =2; i*i <= n; i++){if(n%i ==0){
res = res / i *(i -1);for(; n%i ==0; n /= i);}}if(n !=1) res = res / n *(n -1);return res;}int euler[MAX_N];//O(MAX_N)时间筛出欧拉函数值的表voideuler_phi2(){for(int i =0; i < MAX_N; i++)
euler[i]= i;for(int i =2; i < MAX_N; i++){if(euler[i]== i){for(int j = i; j < MAX_N; j += i)
euler[j]= euler[j]/ i *(i -1);}}}
线性同余方程组
详情请移步:求解线性同余方程组 下面给大家介绍一下如何求解由多条线性同余方程联立得到的线性同余方程组。用数学化的符号表示就是求解 ai×x≡bi(modm)(1≤i≤n) 这样的方程组。如果方程组有解,那么一定有无穷多解,而且解的全集一定可以写成 x≡b(modm) 的形式,因此问题就转化为求解 b 和 m 。如果我们能求解方程组 x≡b1(modm1) , a×x≡b2(modm2) ,那么只要对方程逐个求解,对于任意有限的 n 我们就都可以求出答案了。
因为 x≡b(modmi) ,所以可以把 x 写成 x=b1+m1×t 的形式。把它代入第二条式子,可以得到
//返回一个(b,m)的数对
pair<int,int>linear_congruence(const vector<int>&A,const vector<int>&B,const vector<int>&M){//由于最开始没有任何限制,所以先把解设为表示所有整教的 x三0(mod 1)int x =0, m =1;for(int i =0; i < A.size(); i++){int a = A[i]* m, b = B[i]- A[i]* x, d =gcd(M[i], a);if(b%d !=0)returnmake_pair(0,-1);//无解int t = b / d *mod_inverse(a / d, M[i]/ d)%(M[i]/ d);
x = x + m * t;
m *= M[i]/ d;}returnmake_pair(x % m, m);}
中国剩余定理
详情请移步:中国剩余定理证明 我们假设同余方程组里所有的 a 都等于 1 ,并且所有的 m 都互素。这样,答案就一定是 x≡b(modΠmi) 。反之,对于一个合数 n ,我们假设有 n=ab(其中a和b互素) 。那么如果xmodn 的值确定, xmoda 和 xmodb 的值就都确定了。也就是说,我们有 (xmodn)⇔(xmoda,xmodb) 这样一组对应关系。
换句话说,以合数 n 为模数来考虑与以 a 和 b 为模数来考虑是等价的。这个定理叫做中国剩余定理。通过对 n 进行分解,对于模合数的情况只需要考虑模 pk(p为素数) 的情况就可以了。其中,如果 n 不能被任何一个完全平方数整除,那么问题就可以转化为模数为素数的情况,从而变得容易求解。中国剩余定理不是一个算法,而是可以看成在思考算法时的一个提示
例: f(x)≡0(modn)⇔f(x)≡0(modpk)(pk∣n)
n!(n的阶乘)
在计数问题中,经常需要用到 n! 。在学完前面介绍的内容之后,有必要了解 n! 在 modp 下的一些性质。下面我们假设 p 是素数, n!=ape(a无法被p整除) ,并试图求解 amodp 和 e 。e 是n! 能够迭代整除 p 的次数,因此可以使用下面的式子进行计算。
n/p+n/p2+n/p3+…
这个结论很显然,因为 n/d 和不超过 n 的能被 d 整除的正整数的个数相等。由于只需要对于 pt≤n 的 t 进行计算,因此复杂度是 O(logpn) 。
接下来计算 amodp 。首先计算 n!=1×2×…×n 的因数中不能被 p 整除的项的积。假设 n=10,p=3 ,则
从这个例子中可以看出,不能被 p 整除的项在 modp 下呈周期性。因此,不能被 p 整除的项的积等于 (p−1)!(n/p)×(nmodp)! 。事实上,根据威尔逊定理,我们有 (p−1)!≡−1 。因为除了 1 和 p−1 之外其余的项都可以和各自的逆元相乘得到1。
接下来,计算可以被 p 整除的项的积。可以被 p 整除的项有 p,2p,3p,…,(n/p)p 。把这些项分别除以 p 之后得到 1,2,3.…,n/p 。因此,问题的范围就由 n 缩小到了 n/p 。如果预处理出 0≤n<p 范围中 n!modp 的表,就可以在 O(logpn) 时间内算出答案。如果不预处理,那么复杂度是 O(plogpn) 。
//分解n!=a p^e,返回a mod p。 O(1og,n)。intmod_fact(int n,int p,int& e){
e =0;if(n ==0)return1;//计算p的倍数的部分int res =mod_fact(n / p, p, e);
e += n / p;//由于(p-1)!=-1,因此(p-1)!^{(n/p)}只需要知道n/p的奇偶性就可以计算了。if(n / p %2!=0)return res *(p - fact[n % p])% p;return res * fact[n % p]% p;}