zoukankan      html  css  js  c++  java
  • 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
    ", a, t, delta_d);
        l /= t;
        a *= delta_d / t;
        a = (a % l + l) % l;
        printf("%lld", a);
        return 0;
    }
    View Code

      

  • 相关阅读:
    struct xxx enum(在class下,在static void Main上)
    集合( Stack / Queue / Hashtable 都没有索引)
    集合(ArrayList)
    数组(for 循环+等量代换)
    类型(Math 、Datetime 、random )
    语句(语句分类及if语句)
    运算符分类、优先级
    基本类型转换及练习
    语言基础(项目结构、数据类型、变量、常量)
    进制转换(二进制、八进制、十进制与十六进制之间的相互转换)
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7337301.html
Copyright © 2011-2022 走看看