「一本通 6.4 例 2」同余方程

GitHub跳转原题关系图返回列表

用扩展欧几里得求 ax + by = 1 的特解,再把 x 取模调到最小正整数解。

OJ: roj

题目 ID: 1632

难度:入门

标签:数论扩展欧几里得同余方程

创建: 2026-09-30 23:08

更新: 2026-10-06 01:24

题目描述

求同余方程 ax≡1(modb)ax \equiv 1 \pmod b 的最小正整数解。输入一行两个正整数 a,ba, b(2≤a,b≤2×1092 \le a, b \le 2 \times 10^9),保证有解;输出最小正整数解 x0x_0。样例输入 3 10,输出 7。

思路

ax≡1(modb)ax \equiv 1 \pmod b 等价于 ax+by=1ax + by = 1,因保证有解故 gcd⁡(a,b)=1\gcd(a, b) = 1。用扩展欧几里得求出一组特解 xx,通解为 x+kbx + kb,把 xx 取模调整到 [1,b][1, b] 即为答案。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 23:08
# update_at: 2026-09-30 23:08

import sys


def exgcd(a: int, b: int) -> tuple[int, int, int]:
    """扩展欧几里得算法:返回 (g, x, y) 使得 a*x + b*y = g = gcd(a, b)。"""
    if b == 0:
        return a, 1, 0
    g, x1, y1 = exgcd(b, a % b)
    return g, y1, x1 - (a // b) * y1


def solve() -> None:
    data = sys.stdin.read().split()
    if not data:
        return
    a, b = map(int, data)
    _, x, _ = exgcd(a, b)
    # 调整为最小正整数解
    ans = (x % b + b) % b
    print(ans if ans != 0 else b)


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-06 01:24
 * update_at: 2026-10-06 01:24
 */
#include <iostream>

typedef long long ll;

// 扩展欧几里得:求出 a*x + b*y = gcd(a, b) 的一组特解 x, y
ll exgcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll g = exgcd(b, a % b, x, y);
    ll nx = y;
    ll ny = x - (a / b) * y;
    x = nx;
    y = ny;
    return g;
}

int main() {
    ll a, b;
    std::cin >> a >> b;

    ll x, y;
    exgcd(a, b, x, y);

    // 通解为 x + k*b,把特解调整到 [1, b] 内的最小正整数
    ll ans = (x % b + b) % b;
    if (ans == 0) {
        ans = b;
    }
    std::cout << ans << std::endl;
    return 0;
}