整数与整除

本文介绍扩展欧几里得算法及其应用,包括裴蜀定理、求解线性方程组等,并讨论了逆元的概念及快速求解方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

整数与整除

扩展欧几里得算法

  • 裴蜀定理:若 a , b ∈ Z a,b\in Z a,bZ,对于任意整数 x , y x,y x,y a x + b y = k gcd ⁡ ( a , b ) \color{red}ax+by=k\gcd(a,b) ax+by=kgcd(a,b)。特别的,存在 x , y x,y x,y,使得 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)

    用来判断式子是否有解: a x + b y = m ax+by=m ax+by=m 有解    ⟺    gcd ⁡ ( a , b ) ∣ m \iff \gcd(a,b)|m gcd(a,b)m

    • 证明

      d = gcd ⁡ ( a , b ) d=\gcd(a,b) d=gcd(a,b),则 d ∣ ( a x + b y ) d|(ax+by) d(ax+by)

      不妨设 s s s a x + b y ax+by ax+by 的最小正值,则 ∵ d ∣ s ∴ d ≤ s \because d|s\therefore d\le s dsds

      q = a / s , r = a % s q=a/s,r=a\%s q=a/s,r=a%s,即 a = q s + r a=qs+r a=qs+r.

      ∴ r = a − q ( a x + b y ) = a ( 1 − q x ) + b ( − q y ) \therefore r=a-q(ax+by)=a(1-qx)+b(-qy) r=aq(ax+by)=a(1qx)+b(qy),即 r r r a , b a,b a,b 的线性组合。

      ∵ 0 ≤ r < s    且    s 为 最 小 正 值 ∴ r = 0 , a = q s \because 0\le r<s\;且\;s为最小正值 \therefore r=0,a=qs 0r<ssr=0,a=qs,即 s ∣ a s|a sa.

      同理 s ∣ b s|b sb.

      s s s a , b a,b a,b 的公约数,于是 ∵ s ∣ d ∴ s ≤ d \because s|d\therefore s\le d sdsd.

      于是 s = d s=d s=d 得证。

    • 推论 a , b a,b a,b 互质    ⟺    \iff 存在整数 x , y x,y x,y,使得 a x + b y = 1 ax+by=1 ax+by=1

  • 扩展欧几里得

    • 目的:计算 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b) 的解 x , y x,y x,y

    • 方法:根据普通辗转相除法,到达递归边界 b=0,a=gcd(a,b) 时,发现有解 x = 1 , y = 0 x=1,y=0 x=1,y=0,即 a ∗ 1 + b ∗ 0 = gcd ⁡ ( a , b ) a*1+b*0=\gcd(a,b) a1+b0=gcd(a,b)

    • 注意:此时 a , b a,b a,b 已不是开始的 a , b a,b a,b,于是根据递归算法和下一状态 b , a % b b,a\%b b,a%b 的通解 x 1 , y 1 x_1,y_1 x1,y1(即 b ∗ x 1 + ( a % b ) ∗ y 1 = gcd ⁡ b*x_1+(a\%b)*y_1=\gcd bx1+(a%b)y1=gcd)求出当前状态的通解。
      ∵ a % b = a − ( a / b ) ∗ b ∴ b ∗ x 1 + ( a % b ) ∗ y 1 = b ∗ x 1 + ( a − ( a / b ) ∗ b ) ∗ y 1 = a ∗ y 1 + b ∗ ( x 1 − a / b ∗ y 1 ) = gcd ⁡ 即 { x = y 1 y = x 1 − a / b ∗ y 1 \because a\%b=a-(a/b)*b\\ \therefore b*x_1+(a\%b)*y_1=b*x_1+(a-(a/b)*b)*y_1=a*{\color{red}y_1}+b*{\color{red}(x_1-a/b*y_1)}=\gcd\\ 即\begin{cases}x=y_1\\y=x_1-a/b*y_1 \end{cases} a%b=a(a/b)bbx1+(a%b)y1=bx1+(a(a/b)b)y1=ay1+b(x1a/by1)=gcd{x=y1y=x1a/by1

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

例题:P2613 【模板】有理数取余

  • 题目:计算有理数 a b ( m o d p ) \dfrac{a}{b} \pmod{p} ba(modp) 的最小正数解

  • 思路:即 a ≡ b x ( m o d p ) a\equiv bx\pmod{p} abx(modp),也就是 b x ≡ 1 ( m o d p ) bx\equiv1\pmod{p} bx1(modp) 的解的 a a a 倍。处理大数据时只需要用 a % p , b % p a\%p,b\%p a%p,b%p 代替 a , b a,b a,b 即可。

    //计算 b * x (mod mod) == a 的最小正数解.即 b * x (mod mod) == 1 的解的 a 倍。
    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define ll long long
    const int mod = 19260817;
    ll a = 0, b = 0, x = 0, y = 0;
    string A, B;
    ll exgcd(ll a, ll b, ll &x, ll &y){
        if(b == 0){
            x = 1, y = 0;
            return a;
        }
        ll gcd = exgcd(b, a % b, x, y);
        ll tmp = y;
        y = x - (a / b) * y;
        x = tmp;
        return gcd;
    }
    int main(){
        cin >> A >> B;
        rep(i, 0, A.length() - 1){
            (a *= 10) += (A[i] - '0');
            a %= mod;
        }
        rep(i, 0, B.length() - 1){
            (b *= 10) += (B[i] - '0');
            b %= mod;
        }
        if(b == 0 && a != 0){
            puts("Angry!");
            return 0;
        }
        exgcd(b, mod, x, y);
        x *= a;
        x = (x % mod + mod) % mod;
        cout << x << endl;
    }
    

例题:P1516 青蛙的约会

  • 题目:计算 x x + m x ( m o d L ) = y y + n x ( m o d L ) xx+mx\pmod{L}=yy+nx\pmod{L} xx+mx(modL)=yy+nx(modL) 的最小正数解 x x x

  • 思路
    ( n − m ) x ≡ x x − y y ( m o d L ) a x ≡ c ( m o d b ) a x + b y = c \begin{aligned} (n-m)x&\equiv xx-yy\pmod{L}\\ ax&\equiv c\pmod{b}\\ ax+by&=c \end{aligned} (nm)xaxax+byxxyy(modL)c(modb)=c

    • 有解    ⟺    gcd ⁡ ( a , b ) ∣ c \iff\gcd(a,b)|c gcd(a,b)c,其中 a = n − m , b = L , c = x x − y y a=n-m,b=L,c=xx-yy a=nm,b=L,c=xxyy

    • 若有解,可用扩展欧几里得求出满足 a x 0 + b y 0 = gcd ⁡ ( a , b ) ax_0+by_0=\gcd(a,b) ax0+by0=gcd(a,b) 的解。然后满足 a x + b y = c ax+by=c ax+by=c 的解即为 x 1 = c gcd ⁡ ( a , b ) x 0 x_1=\dfrac{c}{\gcd(a,b)}x_0 x1=gcd(a,b)cx0,则任意解为 x = x 1 + k b gcd ⁡ ( a , b ) x=x_1+k\dfrac{b}{\gcd(a,b)} x=x1+kgcd(a,b)b

      要求最小正数的特解,只需要 x = ( x % r + r ) % r , 其 中 r = b gcd ⁡ ( a , b ) x=(x\%r+r)\%r,其中r=\dfrac{b}{\gcd(a,b)} x=(x%r+r)%r,r=gcd(a,b)b

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    #define ll long long
    ll x, y, m, n, L, xx, yy, a, c, g;
    ll exgcd(ll a, ll b, ll &x, ll &y){  //求出 ax + by = gcd(a,b) 的特解
        if(b == 0){
            x = 1, y = 0;
            return a;
        }
        ll gcd = exgcd(b, a % b, x, y);
        ll tmp = y;
        y = x - (a / b) * y;
        x = tmp;
        return gcd;
    }
    int main(){
        cin >> xx >> yy >> m >> n >> L;
        m %= L, n %= L, xx %= L, yy %= L;
        a = n - m, c = xx - yy;
        if(a < 0) a *= -1, c *= -1;
        g = exgcd(a, L, x, y);
        if(c % g != 0){
            puts("Impossible");
            return 0;
        }
        x *= c / g;
        x = (x % (L / g) + (L / g)) % (L / g);
        cout << x << endl;
    }
    

逆元

  • 单独求某个数逆元:扩展欧几里得 O ( log ⁡ n ) O(\log n) O(logn)

  • 统一求 1 ∼ n 1\sim n 1n 中每个数关于 p p p 的逆元:线性求逆元 O ( n ) O(n) O(n),单独求每个数花费约 O ( n 1 3 ) O(n^{1\over 3}) O(n31)

    • 代码

      inv[1] = 1;
      for (int i = 2; i <= n; ++i) {
        inv[i] = (long long)(p - p / i) * inv[p % i] % p;
      }
      
    • 证明

      首先 1 − 1 ≡ 1 ( m o d p ) 1^{-1}\equiv1\pmod p 111(modp). 要求 i − 1 ( m o d p ) i^{-1}\pmod p i1(modp)

      k = p / i , r = p % i k=p/i,r=p\%i k=p/i,r=p%i,有 p = k i + r p=ki+r p=ki+r,则 k i + r ≡ 0 ( m o d p ) ki+r\equiv 0\pmod p ki+r0(modp)

      两边同乘 i − 1 × r − 1 i^{-1}\times r^{-1} i1×r1 i − 1 ≡ − k r − 1 ( m o d p ) i^{-1}\equiv -kr^{-1}\pmod p i1kr1(modp),即 i − 1 ≡ − ( p / i ) ∗ ( p % i ) − 1 ( m o d p ) \color{red}i^{-1}\equiv -(p/i)*(p\%i)^{-1}\pmod p i1(p/i)(p%i)1(modp)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值