数论专题
欧几里得
它是我们求解整数 \(a,b\) 的最大公约数的算法。
前置知识
\(max(a,b)+min(a,b)=a+b\)
\(max(a,b)=a+b-min(a,b),min(a,b)=a+b-max(a,b)\)
过程
不妨设 \(a>b\)
我们发现如果 \(b\) 是 \(a\) 的约数,那么 \(b\) 就是 \(a,b\) 的最大公约数,现在考虑 \(b\) 不是 \(a\) 的约数时的情况。
设 \(a=b \times q+r\),其中 \(r<b\),我们可以通过证明 $ gcd(a,b)=gcd(b,a\mod b)$。
此时显然有 \(r=a \mod b\),则 \(r=a-b \times q\),设 \(d|a,d|b\),则 \(\frac{r}{d}=\frac{a}{d}-\frac{b}{d}q\)。
由右边式子可知 \(\frac{r}{d}\) 为整数,即 \(d|r\) ,所以对于 \(a,b\) 的公约数,它也会是 \(b,a \mod b\) 的公约数。
反过来也需证明,设 \(d|a\mod b,d|b\),则 \(\frac{a \mod b}{d}+\frac{b}{d}q=\frac{a}{d}\),由左边式子可知 \(\frac{a}{d}\) 为整数,即 \(d|a\),所以 \(b,a \mod b\)的公约数也会是 \(a,b\) 的公约数。
既然两式的公约数相同,则两式的最大公约数也一定相同。
所以得到式子 \(gcd(a,b)=gcd(b,a \mod b)\)。
注:根据以上说明,可知两个数的最大公约数的约数一定包含两个数的公约数。
代码
int gcd(int a, int b) {
while (b != 0) {
int tmp = a;
a = b;
b = tmp % b;
}
return a;
}
多个数的最大公约数
显然答案是每个数的约数,那么也一定等于每相邻两个数的约数,那么我们每次取出两个数求出它们的最大公约数,再放回去,然后删除这两个数,此时这个公约数就包含了两个数的所有约数。 直至剩下的数的个数为 \(1\) ,就停止。
最小公倍数
两个数
根据算术基本定理,设 \(a=p1^{ka_1}p2^{ka_2}...ps^{ka_s},b=p1^{kb_1}p2^{kb_2}...ps^{kb_s}\)
我们发现两者的最大公因数为:
\(p1^{min(ka_1,kb_1)}p2^{min(ka_2,kb_2)}...ps^{min(ka_s,kb_s)}\)
最小公倍数为:
\(p1^{max(ka_1,kb_1)}p2^{max(ka_2,kb_2)}...ps^{max(ka_s,kb_s)}\)
由于 \(k_a+k_b=max(k_a,k_b)+min(k_a,k_b)\)。
所以得到的结论为 \(gcd(a,b) \times lcm(a,b)=a \times b\)。
根据结论,先求出两数的最大公因数,再求出两数的最小公倍数即可。
多个数
对于一个数列 \(a_1,a_2,...,a_n\) ,所以 \(a_1=p_1^{b1_1}p_2^{b1_2}...p_s^{b1_s},a_2=p_1^{b2_1}p_2^{b2_2}...p_s^{b2_s}...,a_n=p_1^{bn_1}p_2^{bn_2}...p_s^{bn_s}\) ,还是一样,假设现在处理到第\(i\)个数,前\(i-1\)个数的最小公倍数为 \(m\) ,很显然 \(m=p_1^{max(b1_1,b2_1,...,bi-1_1)}p_2^{max(b1_2,b2_2,...,bi-1_2)}...p_s^{max(b1_s,b2_s,...,bi-1_s)}\),\(a_i=p_1^{bi_1}p_2^{bi_2}...p_s^{bi_s}\),所以前 \(i\) 个数的最小公倍数应为 \(m1=p_1^{max(b1_1,b2_1,...,bi_1)}p_2^{max(b1_2,b2_2,...,bi_2)}...p_s^{max(b1_s,b2_s,...,bi_s)}\) ,我们发现 \(gcd(m,a_i)=p_1^{min(max(b1_1,b2_1,...,bi-1_1),bi_1)}p_2^{min(max(b1_2,b2_2,...,bi-1_2),bi_2)}...p_s^{min(max(b1_s,b2_s,...,bi-1_s),bi_s)}\)
\(m \times a_i=p_1^{max(b1_1,b2_1,...,bi-1_1)+bi_1}p_2^{max(b1_2,b2_2,...,bi-1_2)+bi_2}...p_s^{max(b1_s,b2_s,...,bi-1_s)+bi_s}\)
则 \(m \times a_i \div gcd(m,a_i)=p1^{max(b1_1,b2_1...,bi-1_1)+bi_1-min(max(b1_1,b2_1,...,bi-1_1),bi_1)}...ps^{max(b1_s,b2_s...,bi-1_s)+bi_s-min(max(b1_s,b2_s,...,bi-1_s),bi_s)}\)
当 \(max(b1_1,b2_1...bi-1_1) \leq bi_1\)时,\(max(b1_1,b2_1...,bi-1_1)+bi_1-min(max(b1_1,b2_1,...,bi-1_1),bi_1)=bi_1\),
反之有
\(max(b1_1,b2_1...,bi-1_1)+bi_1-min(max(b1_1,b2_1,...,bi-1_1),bi_1)=max(b1_1,b2_1...,bi-1_1)\)
。
所以最终结果均满足是最大值,故得证。
方法二:
\(m \times a_i \div gcd(m,a_i)=p1^{max(b1_1,b2_1...,bi-1_1)+bi_1-min(max(b1_1,b2_1,...,bi-1_1),bi_1)}...ps^{max(b1_s,b2_s...,bi-1_s)+bi_s-min(max(b1_s,b2_s,...,bi-1_s),bi_s)}\)
将 \(max(b1_1,b2_1...,bi-1_1)+bi_1-min(max(b1_1,b2_1,...,bi-1_1),bi_1)\) 的 \(max(b1_1,b2_1...,bi-1_1)\) 看作 \(A\) ,\(bi_1\) 看作 \(B\) ,则原式化为 \(A+B-min(A,B)\) 根据前置知识可知 \(max(A,B)=A+B-min(A,B)\) 。
故得证。
代码如下:
int gcd(int a,int b)
{
if(!b)return a;
return gcd(b,a%b);
}
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int m=a[1];
for(int i=2;i<=n;i++)
m=m*a[i]/gcd(m,a[i]);
裴蜀定理
对于任意正
整数 \(a\) ,\(b\),存在一对整数 \(x,y\) ,满足 \(ax+by=gcd(a,b)\)
感性理解一下,我们发现因为 \(x,y\) 为整数,所以 \(ax+by\) 为 \(gcd(a,b)\) 的倍数,所以一定存在一组 \(x',y'\) 使得 \(ax+by=gcd(a,b)\)。
那么感性理解完毕,我们开始证明。
设 \(d=gcd(a,b)\),则 \(ax+by=\frac{a}{d}\times d\times x+\frac{b}{d}\times d\times y=\frac{c}{d}\times d\)。
两边去掉 \(d\) 得:\(\frac{a}{d}\times x+\frac{b}{d}\times y=\frac{c}{d}\),因为 \(\frac{a}{d}\) 为整数,\(\frac{b}{d}\) 也为整数, \(x,y\) 也为整数,根据“整数 \(\times\) 整数 \(=\) 整数,整数 \(+\) 整数 \(=\) 整数”的封闭法则得 \(\frac{c}{d}\) 一定为整数,也就是 \(d|a\)。
故得证。
扩展欧几里得
它是一般我们求解形如 \(ax+by=c\) 的方程时的算法。
根据裴蜀定理,我们可以很轻松地知道 \(gcd(a,b)|c\) 时才会有整数解。
设 \(ax_1+by_1=gcd(a,b)\)
\(bx_2+(a \mod b)y_2=gcd(b,a\mod b)\)
由欧几里得定理可知 \(gcd(a,b)=gcd(b,a \mod b)\)
所以 \(ax_1+by_1=bx_2+(a \mod b)y_2\)
又因为 \(a \mod b=a- \lfloor \frac{a}{b} \rfloor\times b\),
所以上式化为: \(ax_1+by_1=bx_2+(a- \lfloor \frac{a}{b} \rfloor\times b)y_2\)
所以:\(ax_1+by_1=bx_2+ay_2- \lfloor \frac{a}{b} \rfloor\times b\times y_2=ay_2+b\times(x_2-\lfloor \frac{a}{b}\rfloor \times y_2)\)
假设我们已经先求出了 \(x_2,y_2\),因为 \(a=a\),\(b=b\),则 \(x_1=y_2\),\(y_1=(x_2-\lfloor \frac{a}{b}\rfloor \times y_2)\).
所以求解这种问题就可以转化成求解最大公约数的过程了。
注:边界情况当 \(b=0\) 时,所以 \(gcd(a,b)=a\),\(ax'+by'=gcd(a,b)=a\)。
则原式化为:\(ax'=a\),则 \(x'=1,y'\) 取任意实数,但一般如果你不想爆 \(long~~long\) 的话,最好是 \(y'=0\) 。
代码
int Exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
int d = Exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - (a / b) * y;
return d;
}
例题:青蛙的约会
显然,青蛙\(A\)走的路程为\(x+km\),青蛙\(B\)走的路程为\(y+kn\),则题意要求\(x+km\mod L=y+kn \mod L\),即\(x+km \equiv y+kn(\mod L)\)。
将上式化为一般方程为:\(k(m-n)+zL=y-x\),因为\(m,n,L,y,x\)都是已知量,所以这个方程就相当于关于\(k,z\)的二元一次不定方程。
\(Code\)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int exgcd(int a,int b,LL &x,LL &y){
if(b==0){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main(){
int a,b,m,n,l,f;
//cin>>f;
//while(f--){
cin>>a>>b>>m>>n>>l;
LL x=0,y=0;
int d=exgcd(m-n,l,x,y);
if((b-a)%d!=0){
cout<<"Impossible"<<endl;
}else{
int t3=b-a;
x=x*t3/d;
y=y*t3/d;
int t=abs(l/d);
cout<<(x+t)%t<<endl;
}
//}
return 0;
}