• [数论]拓展欧几里得算法


    欧几里得算法(辗转相除法)

    用来求解最大公约数

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

    在 #include<algorithm> 中也可以直接调用 __gcd(a,b)


    拓展欧几里得算法

    求解不定方程:

    引理:存在 x , y 使得 ax+by=gcd(a,b)

    设a,b,c为任意整数,若方程ax+by=c的一组解是(x0,y0),则它的任意整数解都可以写成(x0+k*b/gcd(a,b),y0-k*a/gcd(a,b)),k取任意整数

     1 typedef long long ll;
     2 
     3 ll exgcd(ll a,ll b)
     4 {
     5     if(b){
     6         ll r=exgcd(b,a%b);
     7         ll k=x;
     8         x=y;
     9         y=k-a/b*y;
    10         return r;
    11     }
    12     else{
    13         x=1,y=0;
    14         return a;
    15     }
    16 }

    解线性同余方程

    关于 x 的模方程 ax%b=c 的解,方程转换为 ax+by=c 其中 y 一般为非正整数,则问题变为用 exgcd 解不定方程


    计算乘法逆元 

    若 a*x≡1(mod b) ,且 a与 b互质,那么我们就能定义: x为 a的逆元

    这就是利用拓欧求解线性同余方程 a*x≡c(mod b) 的 c=1 的情况。我们就可以转化为解 a*x + b*y = 1这个方程

     1 typedef long long ll;
     2 
     3 void exgcd(ll a,ll b)//扩展欧几里得算法求乘法逆元,x为a的逆元
     4 {
     5     if(!b){
     6         x=1,y=0;
     7         return;
     8     }
     9     exgcd(b,a%b);
    10     ll k;
    11     k=x;
    12     x=y;
    13     y=k-(a/b)*y;
    14 }

    一些例题

    zoj 3609

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll gcd;
     5 
     6 ll exgcd(ll a,ll b,ll &x,ll &y)
     7 {
     8     if(b==0){
     9         x=1,y=0;
    10         return a;
    11     }
    12     ll ans=exgcd(b,a%b,x,y);
    13     ll temp=x;
    14     x=y;
    15     y=temp-a/b*y;
    16     return ans;
    17 }
    18  
    19 ll cal(ll a,ll b,ll c)
    20 {
    21     ll x,y;
    22     gcd=exgcd(a,b,x,y);
    23     ll ans=(x%b+b)%b;
    24     if(!ans)
    25         ans=b;
    26     return ans;
    27 }
    28  
    29 int main()
    30 {
    31     ll a,b,t;
    32     cin>>t;
    33     while(t--){
    34         cin>>a>>b;
    35         ll ans=cal(a,b,1);
    36         if(gcd!=1)
    37             cout<<"Not Exist
    ";
    38         else 
    39             cout<<ans<<endl;
    40     }
    41     return 0;
    42 }

    zoj 3593

     1 /*根据公式ax+by=c;当x,y同号时等于max(x,y)
     2 当a,b异号时等于(abs(x)+abs(y))
     3 因为a,b大于0,所以不管x,y同号还是异号都是当x,y,最接近时,答案最小
     4 写出通式 x=x1+b/(gcd)*k, y=y1-a/gcd*k
     5 假设x,y相等, k=(y-x)/(a+b),因为x,y不一定相等,所以枚举k附近的点*/
     6 #include<bits/stdc++.h>
     7 using namespace std;
     8 typedef long long ll;
     9 ll x,y;
    10 
    11 ll exgcd(int a,int b){
    12     if(b){
    13         ll n=exgcd(b,a%b);
    14         ll xt=x;
    15         x=y,y=xt-a/b*y;
    16         return n;
    17     }
    18     x=1,y=0;
    19     return a;
    20 }
    21 
    22 int main(){
    23     ll n,m,t,a,b,c;
    24     cin>>t;
    25     while(t--){
    26         cin>>n>>m>>a>>b;
    27         c=n-m;
    28         ll ans=exgcd(a,b);
    29         if(c%ans!=0){
    30             cout<<-1<<endl;
    31             continue;
    32         }
    33         c/=ans,a/=ans,b/=ans;
    34         x*=c,y*=c;
    35         ll k=(y-x)/(a+b);
    36         ans=10000000000ll;
    37         for(ll i=k-1;i<k+2;i++){
    38             ll xx;
    39             ll x0=x+b*i,y0=y-a*i;
    40             if(x0<=0&&y0>=0||y0<=0&&x0>=0)
    41                 xx=abs(x0)+abs(y0);
    42             else
    43                 xx=max(abs(x0),abs(y0));
    44             if(xx<ans)
    45                 ans=xx;
    46         }
    47         cout<<ans<<endl;
    48     }
    49     return 0;
    50 }

    poj 1061

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 typedef long long ll;
     5 ll x,y;
     6 
     7 ll exgcd(ll a,ll b)
     8 {
     9     if(b){
    10         ll r=exgcd(b,a%b);
    11         ll k=x;
    12         x=y;
    13         y=k-a/b*y;
    14         return r;
    15     }
    16     else{
    17         x=1,y=0;
    18         return a;
    19     }
    20 }
    21 
    22 int main()
    23 {
    24     ll p,q,m,n,l;
    25     scanf("%lld%lld%lld%lld%lld",&p,&q,&m,&n,&l);
    26         ll a=n-m,b=l,c=p-q;
    27         ll ans=exgcd(a,b);
    28         if(c%ans)
    29             printf("Impossible
    ");
    30         else{
    31             ll k=c/ans,t=b/ans;
    32             x*=k;
    33             if(t<0)
    34                 t=-t;
    35             x=(x%t+t)%t;
    36             cout<<x<<endl;
    37         }
    38     return 0;
    39 }

    hdu 1576

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll x,y;
    
    ll exgcd(int a,int b){
        if(b){
            ll n=exgcd(b,a%b);
            ll xt=x;
            x=y,y=xt-a/b*y;
            return n;
        }
        x=1,y=0;
        return a;
    }
    
    int main(){
        ll n,m,t,a,b=9973,c;
        cin>>t;
        while(t--){
            cin>>n>>a;
            ll ans=exgcd(a,b);
            x=(x%b+b)%b;
            ans=n*(x%b)%b;
            cout<<ans<<endl;
        }
        return 0;
    }
    正因为是最弱,所以才理解智慧之强
  • 相关阅读:
    【实践】mysql数据库表设计及存储过程设计
    # Java类链接模型
    java gc
    Spring Data Jpa
    Spring Security
    Amazon SQS 消息队列服务
    JMS概述
    jdk 7&8 new features
    java jri null
    java.lang.OutOfMemoryError: PermGen space
  • 原文地址:https://www.cnblogs.com/Yanick/p/11412108.html
Copyright © 2020-2023  润新知