数论-扩展欧几里得算法

证明链接:http://blog.csdn.net/acmore_xiong/article/details/47694909


 

模板:

void exgcd(ll a,ll b,ll&d,ll&x,ll&y){
    if(!b){
        d=a,x=1,y=0;
        return ;
    }
    exgcd(b,a%b,d,y,x);
    y-=x*(a/b);
} 

 


 一、求解不定方程

 

1.青蛙的约会

题意:

本题其实是在求不定方程的解。根据题设条件,我们其实是需要找到一个整数p,使方程

(x+·m)%L=(y+·n)%L

有解。对L取模可以看成

x+p1·m=y+p1·n+p2·L

合并同类项,得到一个不定方程:

(n-m)·p1+L·p2=x-y

设a=n-m,b=L,c=x-y,如果c%gcd(a,b)==0,方程有解,我们的目的就是求出p1

样例解释:

x=1,y=2,m=3,n=4,L=5

a=(n-m)=1,  b=L=5,  c=x-y=-1

a·p1+b·p2=c → 1·p1+5·p2=-1  ,p1=4,p2=-1

转化为求扩展欧几里得的方程,1·p1’+5·p2’=1(gcd(1,5)=1,并且此时的p1'和p2'是中间解),两边同时乘以-1:(也就是c/r)

1·(-p1’)+5·(-p2’)=-1

1·p1+5·p2=-1

p1-p1',可以求得p1=-1,p2=0.此时求得的解是方程的特解,再加上齐次通解就是方程的通解:

x=p1+k·b

y=p2-k·a

把k=1带入,解得ans=-1+5=4

求特解的代码:(此时p1=1,c=-1,b=5,ans=-1)

ll ans=c*p1-c*p1/b*b;

 

AC代码:

#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 101
#define MAX 1<<30
#define V vector<int>
#define ll long long

using namespace std;

ll gcd(ll a,ll b){
    int c;
    while(b){
        c=a%b;
        a=b;
        b=c;
    }
    return a;
}

void exgcd(ll a,ll b,ll& d,ll& x,ll &y){
    if(!b){
        d=a,x=1,y=0;
        return;
    }
    exgcd(b,a%b,d,y,x);
    y-=(a/b)*x;
}

int main(){
//    freopen("青蛙约会.txt","r",stdin);
    ll x,y,n,m,L,a,b,c,r,p1,p2,d;
    while(~I("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)){
        a=n-m,b=L,c=x-y;
        r=gcd(a,b);
        if(c%r){
            puts("Impossible");
            continue;
        }
        a/=r,b/=r,c/=r;
        exgcd(a,b,d,p1,p2);
        ll ans=c*p1-c*p1/b*b;
//        ll ans=(c/r)*p1;
        while(ans<0)
            ans+=b;
        printf("%lld",ans);
    }
}

 

posted @ 2018-02-20 17:28  TQCAI  阅读(167)  评论(0编辑  收藏  举报