【数论基础】整除,同余初步,欧几里得和扩欧
这篇很杂,我是按照老师讲课顺序打的博客。分别来讲讲
1.整除
a除以非0整数b商为整数,且余数为零,我们就说a能被b整除或说b能整除a,记作b|a。
可整除性的基本性质
若a|b, a|c, 则a|(b+c)
若a|b, 那么对所有整数c, a|bc
若a|b, b|c, 则a|c
整除关系具有传递性.
2.同余
令a为整数,d为正整数,那么有惟一的整数q和r,其中0≤r<d,使得a=dq+r
可以用这个定理来定义除法:d叫除数,a叫被除数,q叫商,r叫余数。
如果两个数a,b除以一个数c的余数相等,说a和b关于模c同余,记作a≡b(mod c)
a≡b(mod c)成立的充要条件是c|(a-b)
3.欧几里得算法
先是最大公约数和最小公倍数,分别用gcd(a,b)和lcm(a,b)表示
那么有a*b==gcd(a,b)*lcm(a,b)
证明:由
可得
那么当我们要求lcm时,可以先求gcd,再求lcm。
再介绍欧几里得算法,又称辗转相除法,古老而强大。
而这是利用了公式gcd(a, b)=gcd(b, a mod b),
时间复杂度为O(logb)
证明:
第一步:令c=gcd(a,b),则设a=mc,b=nc
第二步:可知r =a-kb=mc-knc=(m-kn)c
第三步:根据第二步结果可知c也是r的因数
第四步:可以断定m-kn与n互素【否则,可设m-kn=xd,n=yd,(d>1),则m=kn+xd=kyd+xd=(ky+x)d,则a=mc=(ky+x)dc,b=nc=ycd,故a与b最大公约数≥cd,而非c,与前面结论矛盾】
从而可知gcd(b,r)=c,继而gcd(a,b)=gcd(b,r),得证
代码很简单:
inline int gcd(int a,int b){return b?gcd(b,a%b):a;}//辗转相除
4.扩展欧几里得
裴蜀定理:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。
而扩展欧几里得就是来求这里的x和y的
欧几里得算法的终止条件是x=1,y=0。
先理解一个思路:
设x,y和x1,y1是两组解,且满足:
n由 a*x+b*y = gcd(a,b)
a*x1+b*y1 = gcd(a,b)=gcd(b,a%b)=b*x1+(a%b)*y1
a*x1+b*y1 = gcd(a,b)=gcd(b,a%b)=b*x1+(a%b)*y1
n得 a*x+b*y=b*x1+(a%b)*y1
n设k=a/b,r=a%b,则r=a-k*b,代入上式得
na*x+b*y=b*x1+(a-a/b*b)*y1
na*x+b*y=a*y1+b*(x1-a/b*y1)
n得 x=y1 y=x1-a/b*y1
代码:
inline void ex_gcd(int a,int b){//扩展欧几里得 if(b==0){x=1;y=0;return ;} ex_gcd(b,a%b); int t=x;x=y;y=t-a/b*y; } 或者 inline int ex_gcd(int a,int b){ if(b==0){x=1;y=0;return a;} int tmp=ex_gcd(b,a%b); int t=x;x=y;y=t-a/b*y; return tmp;//这里返回的是最大公因数 }
5.递推的预处理gcd数组
很好理解的,能看懂:
for(int i=0;i<=T;i++) pre[i][0]=pre[0][i]=i; for(int i=1;i<=T;i++)//预处理gcd数组 for(int j=1;j<=i;j++) pre[i][j]=pre[j][i]=pre[j][i%j];
6.拓欧的应用
下一篇讲,后面好多