-
辗转相除法
用途:求解a,b两数的最大公约数
定理: 前提:
语言表述为:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数
有了这个定理,可在几乎是log的时间复杂度内求得最大公约数
int gcd(int a,int b)
{
if(!b) return a;
return gcd(b,a%b);
}
其定理延申:我们知道
而我们知道,
,
则要求,等价于求
因此 ,这样一看,如果求多个数的最大公约,可化成差分的形式
所以一个树状数组维护原差分数组,一个线段树可以区间查询,因此可以维护区间上的最大公约
-
扩展欧几里得
我们想要在辗转相除的过程中,找寻有用的信息,这里有个exgcd详解
扩欧的目标是求解一组的整数解,然后通过扩倍求出通解
首先考虑不定方程有整数解的条件:
很好证明,将上式等号左右同除,等号左侧为整数,要想求得整数解的
,一定会有
,故条件成立
这样,问题转变为求解,我们假设
为该式的一组整数解,等式两边同乘
,导成
,对应
,
考虑如何求上式,首先看看裴蜀定理
故一定存在,使得
,
我们知道左右两式相等,,若想上式对一切
成立,就有
,
,满足递归的条件,因此可以写出代码
void exgcd(int a,int b,int &d,int &x,int &y)
{
if(!b) d=a,x=1,y=0;
else
{
exgcd(b,a%b,d,x,y);
int tmp=x; x=y; y=tmp-(a/b)*y;
}
return ;
}
另一种简短写法:
void exgcd(int a,int b,int &x,int &y)
{
if(!b) {x=1; y=0; return ;}
exgcd(b,a%b,y,x); y-=a/b*x;
return ;
}
-
求解线性同余方程
给定整数,求一整数
满足
,或给出无解,由于未知数指数为1,也叫线性同余方程。
等价为
是
的倍数,不妨设为
倍,于是我们只需要解
即可。
定理:是整数,且
,
,如果
,则方程恰好有
个模
不同余的解,否则无解。
假设为方程的任意一个解,则该方程的
个解分别为:
,其中
以上定理在求最小正整数解时极其适合
int a,b,d,x,y;
int main()
{
a=read(); b=read();
exgcd(a,b,d,x,y);
printf("%d",(x%b+b)%b);
return 0;
}