(本文参考了 镜外之主 dalao 的博客)
一、引入 线性同余方程组
诸多个形如 ax ≡ b (mod p) 的,以x为未知数的一次方程,组成的方程组。
二、引入 数论倒数
引入:
首先,在mod中,仅有加、减、乘法对于mod存在“封闭性”
即
( a + b ) %p = (a %p )+ ( b %p ) √
( a - b ) %p = (a %p )- ( b %p ) √
( a × b ) %p = (a %p )× ( b %p ) √
( a / b ) %p = (a %p )/ ( b %p ) ×
在实际运算中,由于某些过程中间结果过大,long long int都存不下,我们不得不边计算边求余,这时如果我们遇见除法,是不是就完蛋了呢?
当然不是 i(>o<)i,我们拥有一个秘密武器——数论倒数
定义:
如果(a,m)=1且存在唯一的b使得a×b≡1(mod m)且1≤b<m,即b使得 a ≡(1/b)(mod m),则称b为a在模m意义下的数论倒数,记为inv(a)。
简单来说,就是(a / b) % p = (a * inv(a) ) % p = (a % p * inv(a) % p) % p
——这样我们就可以在mod中做"除法"啦 ~(—v—*)~
!Warning:当且仅当(a,p)=1,即a,p互质的时候,a才有在%p环境下的数论倒数!
三、中国剩余定理——解 线性同余方程组
引入
用现代数学的语言来说明的话,中国剩余定理给出了以下的一元线性同余方程组:
有解的判定条件,并用构造法给出了在有解情况下解的具体形式。
中国剩余定理 说明:
方程组有解前提:整数m1,m2, ... ,mn 两两互质,
1 int isHasAnswer(long long int *m)
2 //return 0 == No answer
3 //return 1 == Has answer
4 {
5 int i,j;
6 int flag=0;
7 for(i=1;i<=len_m;i++)
8 for(j=i+1;j<=len_m;j++)
9 {
10 if(gcd(m[i],m[j])==1)//m[i]与m[j]互质
11 {
12 flag=1;
13 return 0;
14 }
15 }
16 return 1;
17 }
则对任意的整数:a1,a2, ... ,an,方程组有解,并且通解可以用如下方式构造得到:
在模的意义下,方程组只有一个解:
四、扩展欧几里得算法
用途:
扩展欧几里得算法 是用来在已知a, b求解一组x,y,
使它们满足贝祖等式: ax+by = gcd(a, b) =d(一定存在整数解,根据数论中的相关定理)。
时间复杂度:
求 n 个不超过 m 的正整数的最大公约数—— O(n+logm)。
代码:
1 /*已知a,b(a>b),求解x,y,满足ax+by=gcd(a,b),并同时返回gcd(a,b)*/
2 int exGcd(int a,int b,int &x,int &y)//x,y使用了引用传递的方式
3 {
4 if(b==0)
5 {
6 x=1;
7 y=0;
8 /*
9 当a%b==0时,显然gcd(a,b)=b,
10 所以b = gcd(a,b) = gcd(b,a%b) = gcd(b,0)
11 此时显然 b*1+0*0 = gcd(b,0) = gcd(a,b)
12 故 x=1,y=0
13 */
14 }
15 else
16 {
17 //g=gcd(a,b)
18 int g = exGcd(b,a%b,x,y);
19 int t = x;
20 x = y;
21 y = t - a/b * y;
22 return g;
23 /*
24 求解 x,y的方法的理解:
25 设 a>b。
26 1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
27 2,a>b>0 时
28 设 ax1+ by1= gcd(a,b);
29 bx2+ (a mod b)y2= gcd(b,a mod b);
30 根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
31 则:ax1+ by1= bx2+ (a mod b)y2;
32 即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
33 也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
34 根据恒等定理得:
35
36 x1=y2;
37 y1=x2- [a / b] *y2;
38
39 这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
40 上面的思想是以递归定义的,因为 gcd 不断的递归求解,一定会有个时候 b=0,
41 所以递归可以结束。
42 */
43 }
44 }