Fork me on GitHub

ACM数论之旅4---扩展欧几里德算法

度娘百科说:

 

首先, ax+by = gcd(a, b) 这个公式肯定有解 (( •̀∀•́ )她说根据数论中的相关定理可以证明,反正我信了)

 

所以 ax+by = gcd(a, b) * k 也肯定有解 (废话,把x和y乘k倍就好了)

 

所以,这个公式我们写作ax+by = d,(gcd(a, b) | d)

 

gcd(a, b) | d,表示d能整除gcd,这个符号在数学上经常见

 

 

 

 

 

那么已知 a,b 求 一组解 x,y 满足 ax+by = gcd(a, b) 这个公式

#include<cstdio>
typedef long long LL;
void extend_Eulid(LL a, LL b, LL &x, LL &y, LL &d){
    if (!b) {d = a, x = 1, y = 0;}
    else{
        extend_Eulid(b, a % b, y, x, d);
        y -= x * (a / b);
    }
}
int main(){
    LL a, b, d, x, y;
    while(~scanf("%lld%lld", &a, &b)){
        extend_Eulid(a, b, x, y, d);
        printf("%lld*a + %lld*b = %lld\n", x, y, d);
    }
}

扩展欧几里德算法的运用2

求解同余方程
已知a,b,m,求x的最小正整数解,使得ax=b(mod m)
通俗讲就是ax mod m=b mod m
那么b是个常数,所以直接b=b%m,不影响结果

 

ax%m=b%m


axax/m×m=b
ax+m×(ax/m)=b


然后两边都有x怎么办?
直接当作x和y的某种关系即可,因为我们只要求x。

 

Ax+By=K
A=a,B=m,K=b

int main()
{
    ll a,b,m;scanf("%lld%lld%lld",&a,&b,&m);
    ll A=a,B=m,K=b;
    ll x,y;
    ll d=ExEuclid(A,B,x,y);
    if(K%d!=0) printf("no solution!");
    else
    {
        x=x*K/d;
        ll t=B/d;
        ll XX=(x%t+t)%t;
        printf("%lld",XX);
    }
}

 

扩展欧几里德算法的运用3

同余方程是这样的:已知a,b,n,求x的最小正整数解,使得ax=b(mod m)
同余方程组是这样:也是求x的最小正整数解,但已知a=1,b数组和m数组
x=b[1](mod m[1])
x=b[2](mod m[2])
x=b[3](mod m[3])
……………………
x=b[n](mod m[n])

 

在x=b(mod m)中,与上一个同理,由于b和m都是常数,可以令b=b%m
即x%m=b
将x当作P以防混淆,并新设x为商(即倍数)
m×x+b=P

 

我们先选取前面两个式子来寻找公共解:
m1×x+b1=P


m2×y+b2=P
①-② m1×x+(m2)×y=b2b1
A=m1,B=-m2,K=b2-b1
调用ExEuclid得到x
等等,不对!B居然是负数!根据前面公约数的描述,不能求负数!
网上无数人忽略了这个问题,反正我是没看到有人说这一句的
那怎么办?实现的时候,我们并不需要y(因为可以由x得出),那么就把B换做正数,求出一个-y即可。
虽然这道题不用,但万一以后碰到这种情况而且还有求y,记得取相反数还原即可

t=B/d
x=x×K/d
最小正整数解XX=(x%t+t)%t

P=m1×XX+b1+LCM(m1,m2)


若干倍的LCM(m1,m2)是因为XX只是其中一个最小正整数解,
仔细思考一下就会发现加上最后这个部分对于①和②都没有影响,x依然是整数
我们要求 同余方程组 的解,就要考虑周全

回归到 x=m1×XX+b1(modLCM(m1,m2))


【提醒一下:因为是模,其实里面已经暗含“若干”了】
最早的格式 x=b(modm)

综上所述:
b=m1×XX+b1


m=LCM(m1,m2)

如此合并,最后一个b就是答案
等到最后一次的时候,因为我们不再需要考虑后面了
将“若干”取0就是最小正整数解了

int main()
{
    int n;scanf("%d",&n);n--;
    ll b1,m1;scanf("%lld%lld",&b1,&m1);b1=b1%m1;
    ll XX;
    while(n--)
    {
        ll b2,m2;scanf("%lld%lld",&b2,&m2);b2=b2%m2;
        ll A=m1,B=m2,K=b2-b1;
        ll x,y;
        ll d=ExEuclid(A,B,x,y);
        if(K%d!=0)
        {
            printf("no solution!");
            return 0;
        }
        else
        {
            x=x*K/d;
            ll t=B/d;XX=(x%t+t)%t;
            b1=m1*XX+b1;
            m1=A*B/d;//LCM(m1,m2)=LCM(A,B)
        }
    }
    printf("%lld",b1);
}

 

 

 

 

LL gcd(LL a, LL b){
    LL t;
    while(b){
        t = b;
        b = a % b;
        a = t;
    }
    return a;
}

posted @ 2018-04-09 16:52  梦想飞的菜鸟  阅读(271)  评论(0编辑  收藏  举报