zoukankan      html  css  js  c++  java
  • 数论3:线性同余方程组

    欧几里得算法

    又称辗转相处法,用以求两个数的最大公约数,引入符号\((a,b)\)表示a、b的最大公约数,\(a|b\)表示a能整除b,\(a\not |\ \ b\)表示a不能整除b。

    现要证明\((a,b) = (b,a \mod b)\)
    即证\(a = bq + r\)\((a,b)=(b,r)\)
    \((a,b) = d_1\)\((b,r) = d_2\)
    \(d_1(a^, - b^,q) = r\),即\(d_1 | r\)
    其已知\(d_1 | b\),所以\(d_1 | (b,r)\),即\(d_1 | d_2\)
    同理有\(d_2 | d_1\),所以得\(d_1 = d_2\)

    因为\((n, 0) = n\),所以这也是欧几里得算法的出口。

    时间复杂度\(O(\lg \max(a,b))\),因为每次迭代数字的大小至少减少一半。

    int gcdr(int a, int b)
    {
        if(b == 0) return a;
        return gcd(b, a%b);
    }
    
    int gcd(int a, int b)
    {
        while(b) {
            int r = a % b;
            a = b, b = r;
        }
        return a;
    }
    

    扩展欧几里得算法

    用以求不定方程\(ax + by = (a,b)\)的一组特解,为方便令\((a,b) = d\),引入符号\(\lfloor \frac a b \rfloor\)表示下取整,讨论其解法。

    \(b=0\)时,特解\(x=1, y=0\)
    \(b\neq 0\),令\(r=a \mod b\)考虑方程

    \[by_1 + rx_1 = (b, r) \]

    因为\((a,b)=(b,r)\),所以

    \[ax + by = by_1 + rx_1 \]

    \(r = a \mod b = a - \lfloor \frac a b \rfloor b\),所以

    \[ax + by = by_1 + (a - \lfloor \frac a b \rfloor b)x_1 \]

    整理得

    \[ax + by = ax_1 + b(y_1 - \lfloor \frac a b \rfloor x_1) \]

    得递归解

    \[x = x_1 \qquad y = y_1 - \lfloor \frac a b \rfloor x_1 \]

    现一组特解为\(x_0, y_0\),则通解为

    \[x = x_0-bt \quad y = y_0 + at \]

    时间复杂度同样为\(O(\lg\max(a,b))\),因为递归的执行次数的决定因素和欧几里得算法一样。

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

    扩展欧几里得算法求\(ax + by = c\)

    可以通过\(ax_0 + by_0 = d\)的特解放大倍数求得。
    \(d \not |\ \ c\),则无解;
    \(d \ \ \, |\ \ c\),则无解有以下讨论:
    两边同时乘\(\frac c d\),可有

    \[a\frac {x_0 c}{d} + b \frac {y_0c}{d} = c \]

    特解为

    \[x_1 = \frac {x_0 c}{d} \quad y_1 = \frac {y_0c}{d} \]

    通解为

    \[x = x_1-\frac b d t \quad y = y_1 + \frac a d t \]

    // 有解返回true,否则false
    bool solve1(int a, int b, int c, int &x, int &y)
    {
        int d = exgcd(a, b, x, y);
        if(c % d != 0) return 0;
        int t = c / d;
        x *= t, y *= t;
        return 1;
    }
    

    扩展欧几里得算法求\(ax \equiv b \pmod m\)

    \(a \equiv b \pmod m\),a、b同余代表除m时余数相同,即\(a - \lfloor \frac a m \rfloor m = b - \lfloor \frac b m \rfloor m\),整理得

    \[mk = a-b,即m | (a-b) (k为整数) \]

    所以上述同余方程可写为:

    \[ax - my = b \]

    这就可以用扩展欧几里得算法求\(ax + by = c\)方法求解了。

    // 有解返回true,否则false
    bool solve2(int a, int b, int m, int &x)
    {
        int y;
        return solve1(a, -m, b, x, y);
    }
    

    线性同余方程组\(a_ix \equiv b_i \pmod{m_i}\)

    我们无法做到一次求解多个方程,那么考虑如何将其化为单一方程求解。

    我们的目标是\(x = b \pmod m\),即b和m。

    为方便解决,引入方程\(x \equiv 0 \pmod 1\),现只需要考虑以下两个方程的合并问题

    \[\begin{cases} x &\equiv b_0 & \pmod {m_0} \quad &①\\ a_1x &\equiv b_1 & \pmod {m_1} \quad &② \end{cases} \]

    由①得到

    \[x=b_0 + m_0u \quad ③ \]

    代入②得

    \[a_1m_0u \equiv b_1 - a_1b_0 \pmod {m_1} \]

    仅当\(d=(a_1m_0, m_1) | (b_1 - a_1b_0)\)时,整个方程组有解。
    通过扩展欧几里得算法求\(ax \equiv b \pmod m\)的方法求得解\(u = u_0 \pmod {\frac {m_1}{d}}\),带回③得,\(x = b_0 + m_0u_0 + \frac {m_0m_1}{d}t\),即

    \[x \equiv b_0 + m_0u_0 \pmod {\frac {m_0m_1}{(a_1m_0, m_1)}} \]

    至此合并完成。

    int n, A[maxn], B[maxn], M[maxn];
    
    // 有解返回true,否则false
    bool solve_equ_set(int &b0, int &m0)
    {
        int u0;
        b0 = 0, m0 = 1;
    
        for(int i = 0; i < n; ++i) {
            int na = A[i] * m0;
            int nb = B[i] - A[i]*b0;
            int d = gcd(na, M[i]);
            if(!solve2(na, nb, M[i], u0)) return 0;
            b0 += m0 * u0;
            m0 *= M[i] / d;
            b0 %= m0;
        }
        return 1;
    }
    
  • 相关阅读:
    Core Expression
    Linux基础
    express
    C#程序模拟登录批量获取各种邮件内容信息
    Windows Phone 执行模型概述
    Wp8—LongListSelector控件使用
    网页背景图片自然缩放
    Unix sed实用教程系列目录[已完成]
    Unix sed实用教程开篇
    《SpringMVC从入门到放肆》十五、SpringMVC之上传文件
  • 原文地址:https://www.cnblogs.com/sequix/p/8524773.html
Copyright © 2011-2022 走看看