辗转相减法
用于求两数的最大公约数。
a和b两数不断地用大数减小数,再用差和较小数重复以上操作直至两数相等。
例如48和56的最大公约数:
56 48->8 48->8 40->8 32->8 24->8 16->8 8.
故答案为8.
为了优化计算常常将减法改为取余。
代码
int gcd(int a,int b)
{
if(a<b) swap(a,b);
while(a!=b&&a&&b)
{
a=a%b;
swap(a,b);
}
return a;
}
此时每进行一次操作问题规模都将缩小一倍,故复杂度为log(n)。
扩展 求解(k1*x+k2 *y=1)
假设k1 > k2
如果解决了这个更小的问题
(k1 - k2) * x_1 + k2 * y _1 = 1
就可以由
k1* x_1+k2*(y_1-x _1) = 1
解出 x_1, y_1即可推出x , y。
代码
#include<bits/stdc++.h>
using namespace std;
int x,y;
int qj(int a,int b)
{
if(b)
{
int k=qj(b,a%b);
x-=(a/b)*y;
swap(x,y);
return k;
}
else
{
x=1;
y=0;
return a;
}
}
int main()
{
int a,b;
cin>>a>>b;
qj(a,b);
cout<<x<<" "<<y;
}
应用 求乘法逆元
乘法逆元
假设要算 C(n, m) % MOD
本质就是算m! / ( (m-n)! * n!) % MOD
答案肯定是个整数,但是要取余,中间又有除法运算
我们知道乘法与加法减法运算都是可以先取余再运算的,不影响结果。但是除法比如
12 / 3 % 5 = 4
12 % 5 / 3 = 0.666666
计算方法
令 a / b % mod = c
则 a / b = k*mod + c
a = k * b * mod + b * c
这个时候 如果可以找到一个数 inv(b) 使得 b * inv(b) % mod = 1
那么我们给两边同时乘上inv(b) 就有
a * inv(b) = k * mod + c
所以我们就可以巧妙的将原先的除法转换成了乘法
那么这个问题的关键就在于b * inv(b) % mod = 1有解
这实际上就是扩展欧几里得判断是否有解,b 与 mod必须互质