浅谈关于欧几里得的一系列算法
--------- 这里有个叫分界线的家伙说,本章的所有讨论均在整数的范围中,所有除法都为带余除法o----------------
朴素欧几里得算法
又名辗转相除法,代码实现如下:
int gcd(int a, int b) // a >= b
{
if(b == 0) return a;
return gcd(b, a % b)
}
想一想为什么可以这样计算?
我们设
\(a=k_1m, \ b=k_2m \ ,gcd(a,b)=m,\ gcd(k_1,k_2)=1\)
很容易发现,当我们进行加减运算的时候,他们的和或者差一定是 \(m\) 的倍数,也就是说最大公约数不改变
既然这样,那么当 \(a\ mod\ b=0\) 的时候可以发现此时的 \(b\) 一定就是最大公约数 \(m\)
而我们为了造出这个特殊情况,我们可以像代码中展示的那样不停的迭代,由于我们始终保证了 \(a>b\) ,所以我们最后一定能得到我们想要的情况,从而得到 \(gcd\)
扩展欧几里得算法
这个算法的用处是用来解形如 \(ax + by = c\) 的不定方程
首先,如果你进行过一点思考的话就为发现必须满足条件 \(c \mid \ gcd(a,b)\) 原方程才有整数解
因此,我们可以把原式变成一个更容易讨论的形式
\(ax+by=gcd(a,b)\ \ (a>=b)\)
由于上面的思考,不难发现
\(\because gcd(a,b)=gcd(b,a\ mod\ b)\)
同上,我们依然讨论一下它的特殊情况,当 \(b=0\) 时,也就是 \(ax + by=a\) 时,显然 \(x=1,\ y=0\)
那么我们要做的就是通过这个临界情况,反推出原方程的一组解
\(\therefore\ \) 我们假设
\(ax_1+by_1=gcd(a,b)\)
\(bx_2+(a\ mod\ b)y_2=gcd(b,a\ mod\ b)\)
然后对这个形式做一些变形
\(\Rightarrow\ ax_1+by_1=bx_2+(a\ mod\ b)y_2\)
\(\Rightarrow\ ax_1+by_1=bx_2+(a-\frac{a}{b}b)y_2\)
\(\Rightarrow\ ax_1+by_1=b(x_2-(\frac{a}{b})y_2)+ay_2\)
又由于恒等定理可得
\(x_1=y_2,\ y_1=x_2-(\frac{a}{b})y_2\)
这样,我们就可以通过 \(x_2,\ y_2\) ,推断出 \(x_1,\ y_1\)
同样的道理,我们也就这样迭代下去,就可以得出那组特殊的解了
由于它的方法和朴素欧几里得算法有莫大的关联,所以我们可以在原来的代码上加上一些神秘的东西,变成扩展欧几里得算法
int exgcd(int aaa, int bbb, int &x, int &y)
{
if(bbb == 0)
{
x = 1;
y = 0;
return aaa;
}
g = exgcd(bbb, aaa % bbb);
int temp = x; x = y; y = temp - aaa / bbb * y;
return g;
}
类欧几里得算法
这个算法其实可以衍生出好几种,接下来我们所讲解的是最基础,也是最经典的那一种
设 \(f(a,b,c,n)=\sum_{i=0}^n\lfloor\frac{ai+b}{c}\rfloor\)
我们要求的这个函数其实可以换个角度来观察
\(f(a,b,c,n)=\sum_{i=0}^n\lfloor\frac{a}{c}i+\frac{b}{c}\rfloor\)
其实这个函数的几何意义是一次函数下 \(x\in [0,n]\) 整点的个数(包含直线上的点,但是不包含 \(y=0\) 的点)
所以我们就可以在这个思想上在进行一些变化
设 \(m=\lfloor\frac{an+b}{c}\rfloor\)
\(f(a,b,c,n)=\sum_{i=0}^n\ \sum_{j=1}^m\ [\frac{ai+b}{c}>=j]\)
\(f(a,b,c,n)=\sum_{i=0}^n\ \sum_{j=0}^{m-1}\ [\frac{ai+b}{c}>=j+1]\)
\(f(a,b,c,n)=\sum_{i=0}^n\ \sum_{j=0}^{m-1}\ [ai>=cj+c-b]\)
\(f(a,b,c,n)=\sum_{i=0}^n\ \sum_{j=0}^{m-1}\ [ai>cj+c-b-1]\)
\(f(a,b,c,n)=\sum_{i=0}^n\ \sum_{j=0}^{m-1}\ [i>=(\frac caj+\frac{c-b-1}a)]\)
\(f(a,b,c,n)=\sum_{j=0}^{m-1}\ [n-(\frac caj+\frac{c-b-1}a)]\)
\(f(a,b,c,n)=nm-\sum_{j=0}^{m-1}\ [\frac caj+\frac{c-b-1}a]\)
\(f(a,b,c,n)=nm-f(c,c-b-1,a,m-1)\)
通过这个变化,就可以递归求解了,时间复杂度和朴素欧几里得算法类似