浅谈关于欧几里得的一系列算法
--------- 这里有个叫分界线的家伙说,本章的所有讨论均在整数的范围中,所有除法都为带余除法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))
由于上面的思考,不难发现
(ecause gcd(a,b)=gcd(b,a mod b))
同上,我们依然讨论一下它的特殊情况,当 (b=0) 时,也就是 (ax + by=a) 时,显然 (x=1, y=0)
那么我们要做的就是通过这个临界情况,反推出原方程的一组解
$ herefore $ 我们假设
(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}^nlfloorfrac{ai+b}{c} floor)
我们要求的这个函数其实可以换个角度来观察
(f(a,b,c,n)=sum_{i=0}^nlfloorfrac{a}{c}i+frac{b}{c} floor)
其实这个函数的几何意义是一次函数下 (xin [0,n]) 整点的个数(包含直线上的点,但是不包含 (y=0) 的点)
所以我们就可以在这个思想上在进行一些变化
设 (m=lfloorfrac{an+b}{c} floor)
(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))
通过这个变化,就可以递归求解了,时间复杂度和朴素欧几里得算法类似