欧几里德算法,扩展欧几里德,中国剩余定理

数论初步讲解时未总结,周日早上刚起感觉有点困,记忆一下。

欧几里德算法:

用于求最大公约数,也可求得最大公倍数,即辗转相除法。

gcd(a,b)=gcd(b,a%b)

例如:设k为a,b的最大公约数

假设 a>b a,b的公约数为k, a=bx+y;
则能推出 a%k==0, b%k==0,a%b==y
由此可得 bx%k==0,(a-bx)%k==0
所以说y%k==0 即 ·a%b%k==0
同理 (b,a%b)的公约数也等于k

int gcd(int a,int b)
{
	return b==0? a:gcd(b,a%b);
}

扩展欧几里德算法:

根据欧几里得算法:

gcd(a,b)=gcd(b,a mod b);

由于a*x+b*y=gcd(a,b)

扫描二维码关注公众号,回复: 8780160 查看本文章

所以我们有:

b*x1+(a mod b)*y1=gcd(b,a mod b);

类比之前的等式: 

化简得到:

=a*y1+b*(x1-a/b*y1);

所以我们有:

x=y1;

y=x1-a/b*y1;

可以用来求二元一次方程的通解。(可用数学归纳法求证)

即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。
那么对二元一次方程 ax+by=m 来说,m是gcd(a,b)的倍数,那么就可以通过递归的方法实现。

gcd(a,b)=g,a'=a/g,b'=b/g;

设a,b,c为任意整数,ax+by=c这个方程的一组整数解,为(x1,y1),那么任意的整数解都可以写成(x1+k*b',y1-k*a'),k取得任意整数。

附上代码:

void exgcd(int a,int b,int &d,int &x,int &y)
{
	if(!b)
	{
		d=a,x=1,y=0;
	}
	else
	{
		gcd(b,a%b,d,y,x);
		y-=x*(a/b);
	}
}
//其他写法
int ex_gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    int t=ex_gcd(b,a%b,x,y);
    int temp=y;
    y=x-(a/b)*y;
    x=temp;
    return t;
}

注意求出的x,y只是一组解,通解在上面已经写明。

中国剩余定理:

定理1:两个数相加,如果存在一个加数,不能被整数a整除,那么它们的和,就不能被整数a整除。

定理2:两数不能整除,若除数扩大(或缩小)了几倍,而被除数不变,则其商和余数也同时扩大(或缩小)相同的倍数(余数必小于除数)。

例题:
问题:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

其实就是求解一次同余式组。

1.求最小公倍数
lcm=3 * 5 * 7=105;
2.求各个数的基础数
(1)105÷3=35
35÷3=11…2 //基础数35
(2)105÷5=21
21÷5=4…1
定理2把(2)的余数扩大3倍得到3,那么被除数也扩大3倍,得到21 * 3=63//基础数63
3、105÷7=15
15÷7=2…1
定理2把1扩大2倍得到2,那么被除数也扩大2倍,得到15 * 2=30//基础数30
3.把得到的基础数加和(注意:基础数不一定就是正数)
35+63+30=128
4、减去最小公倍数lcm(在比最小公倍数大的情况下)
x=128-105=23
那么满足题意得最小的数就是23了

中国剩余定理推导自己可以去看看。

附上代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100],b[100],n;
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    int t=exgcd(b,a%b,y,x);
    y-=x*(a/b);
    return t;
}
int solve()
{
	int i,j;
    int ans=0;
    int lcm=1;
    for(i=1;i<=n;i++)
    {
        lcm*=a[i];//因为例题给出的数两两互质,所以直接乘法可以的到LCM 
    }
    for(int i=1;i<=n;i++)
    {
    	int temp;
        temp=lcm/a[i];
        int x,y,g;
        g=exgcd(temp,a[i],x,y);//求temp*x+a[i]*y==1解出了x,y的一组解 ,直接相乘b[i] 
        x=(x%a[i]+a[i])%a[i];//因为扩展欧几里得求出的解可能有很多组,且可能为负,我们这步求出了一个比a[i]小且大于0的解。
        ans=(ans+x*temp*b[i])%lcm;
    }
    return ans;
}
int main()
{
	int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);//ans%a[i]=b[i].
    }
    int ans=solve();
    printf("%d\n",ans);//  例题: 输入3组数 3 2    5 3    7 2 输出 23 
}


 

发布了56 篇原创文章 · 获赞 17 · 访问量 2340

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/99702420