扩展欧几里得

欧几里得(求最大公约数):

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

扩展欧几里得算法代码

int e_gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int ans=e_gcd(b,a%b,y,x);
      y-=x*(a/b);
    return ans;
}

扩展欧几里得的运用:
使用扩展欧几里德算法解决不定方程的办法:
对于不定整数方程ax+by=c,若 c mod Gcd(a, b)=0,则该方程存在整数解,否则不存在整数解。
上面已经列出找一个整数解的方法,在找到a* x+ b*y = Gcd(a, b)的一组解x0,y0后, x* a+y * b = Gcd(a, b)的其他整数解满足:
x = x0 + b/Gcd(a, b) * t
y = y0 - a/Gcd(a, b) * t(其中t为任意整数)
至于ax+by=c的整数解,只需将x* a+y * b = Gcd(a, b)的每个解乘上 c/Gcd(a, b) 即可。
及x的特解:x*(c/gcd(a,b))
在找到x * a+y * b = Gcd(a, b)的一组解x0,y0后,应该是得到x* a+y * b = c的一组解x1 = x0*(c/Gcd(a,b)),y1 = y0*(c/Gcd(a,b)),
p * a+q * b = c的其他整数解满足:
x = x1 + b/Gcd(a, b) * t
y = y1 - a/Gcd(a, b) * t(其中t为任意整数)

其中若是求x的正整数解
令int m=abs(b/gcd(a,b))

1) if(x<0) x+=m;
2)x=((x%m)+m)%m;

扩展欧几里得专题A
*The Sky is Sprite.
The Birds is Fly in the Sky.
The Wind is Wonderful.
Blew Throw the Trees
Trees are Shaking, Leaves are Falling.
Lovers Walk passing, and so are You.
…………………………..Write in English class by yifenfei

Girls are clever and bright. In HDU every girl like math. Every girl like to solve math problem!
Now tell you two nonnegative integer a and b. Find the nonnegative integer X and integer Y to satisfy X*a + Y*b = 1. If no such answer print “sorry” instead.
Input
The input contains multiple test cases.
Each case two nonnegative integer a,b (0

#include<iostream>*
#include<cstdio>
using namespace std;
long long e_gcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long ans=e_gcd(b,a%b,y,x);
    y-=x*(a/b);
    return ans;
}
//扩展欧几里得模板

int main()
{
    int a,b;
    int ans;
    while(scanf("%d%d",&a,&b)!=EOF)
    {
        long long x,y;
        long long c=1;

        ans=e_gcd(a,b,x,y);
        if(c%ans)
        printf("sorry\n");
        else
        {
            //求最小值的过程
            long long m=b/ans;
            x=x*(c/ans);
        //求x的最小正数解
           x=((x%m)+m)%m; 
            //if(x<0)
            //  x+=m;和(x%m)  意义相同
            y=(c-a*x)/b; 
            printf("%lld %lld\n",x,y);
            //cout<<x<<endl;
            }   
    }
    return 0;
}

这里关于欧几里得和扩展欧几里得的证明和应用解释的很好的(链接

现在写了b题对上个链接证明的理解更加深刻,真的不错!

扩展欧几里得专题B

There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at point A at first and your aim is point B. There are 6 kinds of operations you can perform in one step. That is to go left or right by a,b and c, here c always equals to a+b.
You must arrive B as soon as possible. Please calculate the minimum number of steps.

Input
There are multiple test cases. The first line of input is an integer T(0 < T ≤ 1000) indicates the number of test cases. Then T test cases follow. Each test case is represented by a line containing four integers 4 integers A, B, a and b, separated by spaces. (-231 ≤ A, B < 231, 0 < a, b < 231)
Output
For each test case, output the minimum number of steps. If it’s impossible to reach point B, output “-1” instead.
Sample Input

2
0 1 1 2
0 1 2 4

Sample Output

1
-1

试了好几种才能ac

//b题,x y距离最近时候步数最小

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long e_gcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long ans=e_gcd(b,a%b,y,x);
    y-=x*(a/b);
    return ans;
}


int main()
{
    long long A,B,a,b;
    long long ans;
    int n;
    scanf("%d",&n);
    while(n--)
    {
     scanf("%lld%lld%lld%lld",&A,&B,&a,&b);
     //a*x+b*y=B-A 

        long long x,y;
        long long t;
        long long c=abs(A-B);//c 的正负 

        ans=e_gcd(a,b,x,y);
        if(c%ans)//c 若是正的负的 
        printf("-1\n");
        else
        {
            long long temp;
            long long ans1,ans2; 
            long long m=b/ans;
            //x的特解 
            x=x*(c/ans);
            y=y*(c/ans) ;
           /*求x的最小正数解!->应该是|x|+|y|的最小值 
           x=x0+b/gcd(a,b)*t ;
           y=y0-a/gcd(a,b) *t;
           求使得两个方程最小的t值  t=|x0-y0|*ans/(a+b)*/
           if (x<y)   
           {
             swap(x, y);
             swap(a, b);
           }

           temp = x - y;

           //temp=abs(x-y);
           t=temp*ans/(a+b);

           //距离最近的x,y
           x=x-t*b/ans;//x=x+t*b/ans;
           y=y+t*a/ans;//y=y-t*a/ans;

           //有可能这个t并不是最接近的解 

           if(x*y>0)//xy同号
           {
             ans1=abs(x)>abs(y)?abs(x):abs(y);
           } 
           else//x,y异号 
           {
            ans1=abs(x)+abs(y); 
           }

           //t+1
           x-=b/ans;// x+=b/ans;
           y+=a/ans;// y-=a/ans;
            if(x*y>0)//xy同号
           {
             ans2=abs(x)>abs(y)?abs(x):abs(y);
           } 
           else//x,y异号 
           {
            ans2=abs(x)+abs(y); 
           }
          ans=ans1>ans2?ans2:ans1;

            printf("%lld\n",ans);
            }   
    }
    return 0;
}

扩展欧几里得专题C
The modular modular multiplicative inverse of an integer a modulo m is an integer x such that a-1≡x (mod m). This is equivalent to ax≡1 (mod m).
Input
There are multiple test cases. The first line of input is an integer T ≈ 2000 indicating the number of test cases.
Each test case contains two integers 0 < a ≤ 1000 and 0 < m ≤ 1000.
Output
For each test case, output the smallest positive x. If such x doesn’t exist, output “Not Exist”.
Sample Input
3
3 11
4 12
5 13
Sample Output
4
Not Exist
8
References

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;

int e_gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int ans=e_gcd(b,a%b,y,x);
    y-=x*(a/b);
    return ans;
}

int main()
{
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int a,n;
        int x,y;
        scanf("%d%d",&a,&n); 
        int ans=e_gcd(a,n,x,y);
        if(ans>1)
        printf("Not Exist\n");
        else{
             int i=1;
             while((a*i-1)%n!=0)
               i++;

            /*int m=abs(n/ans);
            if(x<0)
             x+=m;  */
            printf("%d\n",i);
        }

    }
    return 0;
 } 

这道题用的是扩展欧几里得的
3)欧几里德算法求模的逆元:
同余方程ax≡b (mod n),如果 gcd(a,n)== 1,则方程只有唯一解。
在这种情况下,如果 b== 1,同余方程就是 ax=1 (mod n ),gcd(a,n)= 1。
这时称求出的 x 为 a 的对模 n 乘法的逆元。
对于同余方程 ax= 1(mod n ), gcd(a,n)= 1 的求解就是求解方程
ax+ ny= 1,x, y 为整数。这个可用扩展欧几里德算法求出,原同余方程的唯一解就是用扩展欧几里德算法得出的 x 。

扩展欧几里得专题D

要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
Output
对应每组数据输出(A/B)%9973。
Sample Input
2
1000 53
87 123456789
Sample Output
7922
6060

 #include<iostream>
#include<cmath>
#include<cstdio>
const int modn=9973;
using namespace std;
typedef long long ll;

/*分析:((n+k*9973)/B)%9973=x   x为最后需要输出的值 
变形--->  (x+k1*9973)*B=n+k*9973
即为  x*B+(k1*B-k)*9973=n;
a=B,b=9973,c=n; 
*/

int e_gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int ans=e_gcd(b,a%b,y,x);
    y-=x*(a/b);
    return ans;
}




int main()
{
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int n,B;
        int x,y,c,a,b;
        scanf("%d%d",&n,&B); 
        a=B,b=modn;
       e_gcd(a,b,x,y);

        //输出正整数结果 //
        x*=n;

        //x=(x*c)%modn;
        x=(x%modn+modn)%modn;
        //while(x<0)
          //x+=modn;        

        printf("%d\n",x);
    }
    return 0;
 } 

用扩展欧几里得直接算出x的值,Bx+Ny=gcd(B,N)——>N=9973且gcd(B,N)=1 所以直接求出x的值 Bx*n+Ny*n=n——>
所以x=x*n,再判断x的正负求出最后结果。

目前专题里面没有用扩展欧几里德算法求解模线性方程的方法:不过emmm贴上相关代码,下次好理解!

bool modular_linear_equation(int a,int b,int n)
{
    int x,y,x0,i;
    int d=exgcd(a,n,x,y);
    if(b%d)
        return false;
    x0=x*(b/d)%n;   //特解
    for(i=1;i<d;i++)
        printf("%d\n",(x0+i*(n/d))%n);
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值