204. 表达整数的奇怪方式

在这里插入图片描述
输入样例:
2
8 7
11 9

输出样例:
31


想法
   核心:让程序去执行合并的操作
    先用扩展欧几里得算法求得k,然后代入到原式内,此时扩展欧几里得算法求得的结果与原式成整数倍,所以求得的解需要 * (m2-m1)/d

x (mod a1) = m1 (mod a1)
x (mod a2) = m2 (mod a2)
x (mod a3) = m3 (mod a3)
·
·
·

x (mod an) = mn (mod an)

将等式两两合并成一个式子,直到最后只剩下一个式子
合并过程
x mod a1 = m1           =>           x = a1k1 + m1
x mod a2 = m2          =>            x = a2k2 + m2
合并消去x : k1 * a1 - k2 * a2 = m2 - m1
此时将 k1 k2当作x,y ;     a1 a2 当作a,b;
转换为式子 : ax+by = gcd(a,b);
有解条件为: m2-m1 = gcd(a,b) 的倍数 d= gcd(a,b)
解出k:
         k1= k1+k(a2/d) = k1%(a2/d)
         k2= k2+k(a1/d) = k2%(a1/d)
带入③式恒成立
k1= k1+k(a2/d) 代入①式
x = a1k1 + m1 = (k1+k(a2/d))*a1 + m1
化简后:
x = a1k1 + m1 +k (a2 * a1 /d) ④
目标: 求出m和a 获取到新的等式 x = m + ka
再化简 ( 等式右侧的值均已知 )
m= a1k1 + m1 ; a=(a2 * a1/d)
x = m + ka ⑤
再将⑤与下一个方程合并求解

最后 x = m+ka;
因为 m = ankn + mn 和 a = | a2 * a1/d |
此时 x = m+ka; 减去一个数的整数倍等于mod上这个数
所以结果为 x = (m%a + a)%a 防止是负数,所以加上a再 %a
求解得出x 的值

代码

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
int n;
LL exgcd(LL a, LL b, LL &x, LL &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }

    LL d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
LL inline mod(LL a, LL b){
    return ((a % b) + b) % b;
}
int main(){
    scanf("%d", &n);
    LL a1, m1;
    scanf("%lld%lld", &a1, &m1);
    for(int i = 1; i < n; i++){
        LL a2, m2, k1, k2;
        scanf("%lld%lld", &a2, &m2);
        LL d = exgcd(a1, -a2, k1, k2);
        if((m2 - m1) % d){ puts("-1"); return 0; }
        k1 = mod(k1 * (m2 - m1) / d, abs(a2 / d));
        m1 = k1 * a1 + m1;
        a1 = abs(a1 / d * a2);
    }
    printf("%lld\n", m1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值