90分求调
查看原帖
90分求调
770457
csvoner楼主2025/1/26 08:57
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

LL exgcd(LL a, LL b, LL &x, LL &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }

    LL d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}


int main()
{
    int n;
    cin >> n;
	// 合并的思路是:每次把一个新的方程合并到一个现有方程中
    LL x = 0, a1, m1; // 假设我们现有方程是 a1,m1
    cin >> a1 >> m1;
    for (int i = 0; i < n - 1; i ++ )
    {
        LL a2, m2;
        cin >> a2 >> m2;
        // 然后开始合并 
        LL k1, k2; // 首先我们要求出来 k1 和 k2 的值 
        LL d = exgcd(a1, a2, k1, k2);
        // 然后这个方程有解的充要条件是: 
        if ((m2 - m1) % d)
        {
            x = -1;
            break;
        }
		// 如果有解的话,我们用扩展欧几里得求的其实是 k1a1-k2a2=d 的一个值
		// 然后我们要得到的是 m2-m1 的值,然后 m2-m1 是 d 的一个倍数
		// 所以我们要把等式两边同时翻若干倍,把 d 翻成 m2-m1 就可以了 
        k1 *= (m2 - m1) / d;
    	// 那么如果我们求出来一个k1的话,那么k1+k*(a2/d) 都是它的一组解
		// 然后这个题的话数据范围出的比较极限,就我们一定要让每次k都变得比较小
		// 否则的话中间结果会溢出,所以我们中间过程一定要让k变得比较小
		// 即把k1变成一个方程的最小的正整数解 
		
		// 那么我们先把 a2/d 先存下来
		LL t = a2 / d;
		// 然后把我们的k1变成一个最小的正整数解 
        k1 = (k1 % t + t) % t;

        x = k1 * a1 + m1;
		// 然后新的方程的 a 就等于 [a1,a2] 
		
		// 然后我们要把方程变成 x=x0+ka , x=ka+m的形式,m就是m1 
		m1 = a1 * k1 + m1;
		
        a1 = abs(a1 / d * a2); // 求最小公倍数,负的正的都可以,我们这里取一个正的,方便一点 
        
		
    }
	// 结束之后如果有解的话我们输出它的最小正整数解 
    if (x != -1)
	{
		// 最小正整数解还需要对它做一个变形
		x = (m1 % a1 + a1) % a1; // 这里求的是 m1%a1正的余数
		// 因为c++在求余数的时候有个特点,求的不是数学意义上的余数 
	}
	
	cout << x << endl;

    return 0;
}
2025/1/26 08:57
加载中...