题解:AcWing 204 表达整数的奇怪方式

【题目来源】

AcWing:204. 表达整数的奇怪方式 - AcWing题库

【题目描述】

给定 \(2n\) 个整数 \(a_1,a_2,\dots,a_n\)\(m_1,m_2,\dots,m_n\),求一个最小的非负整数 \(x\),满足 \(\forall \in [1,n],x\equiv m_i(mod\ a_i)\)

【输入】

\(1\) 行包含整数 \(n\)

\(2\dots n+1\) 行:每 \(i+1\) 行包含两个整数 \(a_i\)\(m_i\),数之间用空格隔开。

【输出】

输出最小非负整数 ,如果 \(x\) 不存在,则输出 \(-1\)

【输入样例】

2
8 7
11 9

【输出样例】

31

【解题思路】

image

image

image

image

【算法标签】

《AcWing 204 表达整数的奇怪方式》 #数学知识# #同余方程# #扩展中国剩余定理#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

typedef long long LL; // 定义 LL 为 long long 类型

// 扩展欧几里得算法,用于求解 ax + by = gcd(a, b) 的一组整数解
LL exgcd(LL a, LL b, LL &x, LL &y)
{
    if (b == 0) { // 如果 b 为 0,递归终止
        x = 1, y = 0; // 解为 x = 1, y = 0
        return a; // 返回 gcd(a, b)
    }
    LL r = exgcd(b, a % b, x, y); // 递归求解
    LL x1 = x, y1 = y; // 保存递归结果
    x = y1, y = x1 - a / b * y1; // 更新 x 和 y
    return r; // 返回 gcd(a, b)
}

int main()
{
    int n; // 定义整数 n,表示方程的数量
    bool has_answer = true; // 标记是否有解
    LL a1, m1; // a1 和 m1 表示第一个方程的系数和常数项
    cin >> n; // 输入方程的数量
    cin >> a1 >> m1; // 输入第一个方程的系数和常数项

    // 循环处理剩余的 n - 1 个方程
    for (int i = 0; i < n - 1; i++) {
        LL a2, m2; // a2 和 m2 表示下一个方程的系数和常数项
        cin >> a2 >> m2; // 输入下一个方程的系数和常数项
        LL k1, k2; // k1 和 k2 用于存储扩展欧几里得算法的解
        // 使用扩展欧几里得算法求解 a1 * k1 + a2 * k2 = gcd(a1, a2)
        LL d = exgcd(a1, a2, k1, k2);
        // 如果 (m1 - m2) 不能被 gcd(a1, a2) 整除,则无解
        if ((m1 - m2) % d) {
            has_answer = false; // 标记无解
            break; // 跳出循环
        }
        // 调整 k1 和 k2 的值
        k1 = k1 * (m2 - m1) / d;
        k2 = k2 * (m2 - m1) / d;
        LL t = a2 / d;
        // 保证 k1 为最小非负整数解
        k1 = (k1 + t) % t;
        // 更新 m1 的值
        m1 = a1 * k1 + m1;
        // 更新 a1 的值
        a1 = a1 / d * a2;
    }

    if (has_answer) 
        // 输出最小非负整数解
        cout << (m1 + a1) % a1 << endl;
    else 
        // 无解输出 -1
        cout << -1 << endl;

    return 0; // 程序结束
}

【运行结果】

2
8 7
11 9
31
posted @ 2026-02-24 21:55  团爸讲算法  阅读(2)  评论(0)    收藏  举报