bzoj1477 && exgcd学习笔记

exgcd

由于忘记了exgcd,这道题就没做出来。。。

exgcd的用处是求ax+by=gcd(a,b)这样方程的解

大概是这个样子的

void ext_gcd(long long a, long long b, long long &x, long long &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
    }
    else
    {
        ext_gcd(b, a % b, y, x);
        y -= x * (a / b);
    }
}
View Code

证明大概是ax+by=gcd(a,b)

根据gcd的性质bx'+(a%b)y'=gcd(b,a%b) 

这样就是求出了上面这个方程的解,我们要做的就是通过x',y'求出x,y

怎么求呢,就是把方程化回ax+by=gcd(a,b)的形式,由于gcd(a,b)=gcd(b,a%b),所以这样的解是相同的

bx'+(a-a/b*b)y'=c (c=gcd(b,a%b))

ay'+b(x'-a/b*y')=c

那么就有x=y',y=x'-a/b*y'

那么我们就先exgcd(b,a%b,y,x),这样求出了x',y'我们要返回x,y,由于传入了y,x,所以x=y'已经求好了,那么就是y,现在y=x',x=y',那么y=x'-a/b*y',y=y-a/b*x,然后返回就行了

边界条件是b=0,a=...,这样就是ax+by=gcd(a,b),ax+0*y=a,那么自然可以得出x=1,y=0是一组解,顺便也求出了gcd

那么这道题可以列出方程am+y-x=an (mod l),那么移一下项,得出a(m-n)=x-y (mod l),那么相当于求(m-n)*a+b*l=x-y 的最小a的解,这不就是exgcd吗?但是x-y不是gcd(m-n,l),怎么解决呢?

我们先求出一组解,(m-n)*a'+b*l=gcd(m-n,l) 设t=gcd(m-n,l)

如果(x-y)%t != 0那么就没有解,因为如果有一组解,那么左边的式子可以整除t,右边却不能,这很明显矛盾

所以我们对于(m-n)*a'+b*l=gcd(m-n,l) 设t=gcd(m-n,l)得出来的解,两边同乘以(x-y)/t就是原来的那个方程了,那么把a'和b'同时乘以(x-y)/t就得出一组a和b了,但是这不一定是最小的,于是我们要对l/t取模,至于为什么是l/t,具体是这样的

我们可以把刚才那个方程看成一个线性同余方程,那么就是ax=b (mod n)

我们求的是最小解的间隔,这个间隔能帮我们求出最小的正整数解,设这个间隔为d,那么自然a(x+d)=b (mod n)

和ax=b (mod n)减一下就是 a*d=0 (mod n),那么我们可以知道a*d是n和a的公倍数,如果想让d最小,那么a*d应该等于lcm(a,n),a*d=lcm(a,n),因为lcm(a,n)=a*n/gcd(a,n),那么就是a*d=a*n/gcd(a,n)

d=n/gcd(a,n),就是刚才那个l/t,所以这个d和l/t就是原方程解的最小周期,取模就能求出最小解

参考http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html

http://m.blog.csdn.net/LiRewriter/article/details/76762084

Ax+By=C

当C%gcd(a,b)==0有解

A,B,C不管正负

通解:x=x0+bt,y=yo-at

最小正整数解:t=b/gcd(a,b) x=(x%t+t)%t

方程axc(mod b)ax+by=c

求逆元:ax=1(mod b)

相当于求ax+by=1 最小正整数解:x+b*b/gcd(a,b)

#include<bits/stdc++.h>
using namespace std;
long long x, y, m, n, l;
void ext_gcd(long long a, long long b, long long &x, long long &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
    }
    else
    {
        ext_gcd(b, a % b, y, x);
        y -= x * (a / b);
    }
}
int main()
{
    scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &l);
    if(m < n)
    {
        swap(n, m);
        swap(x, y);
    }
    long long delta_v = m - n, delta_d = ((y - x) % l + l) % l, t = __gcd(delta_v, l), a, b;
    if(delta_d % t != 0)
    {
        puts("Impossible");
        return 0;
    }
    ext_gcd(delta_v, l, a, b);
//    printf("a=%lld t=%lld delta_d=%lld\n", a, t, delta_d);
    l /= t;
    a *= delta_d / t;
    a = (a % l + l) % l;
    printf("%lld", a);
    return 0;
}
View Code

 

  

posted @ 2017-08-10 08:40  19992147  阅读(474)  评论(0编辑  收藏  举报