2021-02-10

中国剩余定理例题

(其实和标题没啥关系,重点在于分析

题意

https://www.acwing.com/problem/content/206/

给定 2n 个整数a1,a2,…,an和m1,m2,…,mn,求一个最小的非负整数 x,满足∀i∈[1,n], x≡mi(mod ai)。

输入格式
第1 行包含整数 n。

第 2…n+1行:每 i+1 行包含两个整数ai和mi,数之间用空格隔开。

输出格式
输出最小非负整数 x,如果 x 不存在,则输出 −1。
如果存在 x,则数据保证 x 一定在64位整数范围内。

数据范围
1≤ai≤2^31−1,
0≤mi<ai
1≤n≤25

题解

取 两 个 等 式 , x ≡ m 1 ( m o d   a 1 ) 和 x ≡ m 2 ( m o d   a 2 ) , 取两个等式,x \equiv m_1(mod\ a_1) 和 x \equiv m_2(mod\ a_2), xm1(mod a1)xm2(mod a2),
即 x = k 1 × a 1 + m 1 和 x = k 2 × a 2 + m 2 , 即 x = k_1\times a_1 + m_1 和 x = k_2\times a_2 + m_2, x=k1×a1+m1x=k2×a2+m2
即 k 1 × a 1 + m 1 = k 2 × a 2 + m 2 , 即 k_1\times a_1 + m_1 = k_2\times a_2 + m_2, k1×a1+m1=k2×a2+m2
即 k 1 × a 1 − k 2 × a 2 = m 2 − m 1 , 即 k_1\times a_1 - k_2\times a_2 = m_2 - m_1, k1×a1k2×a2=m2m1,
即 a × x + b × y = d   形 式 即 a \times x + b \times y = d\ 形式 a×x+b×y=d 

两 式 子 有 解 , 即 m 2 − m 1 是 d 的 倍 数 ( d = g c d ( a , b ) = g c d ( a 1 , a 2 ) ) 两式子有解,即 m_2 - m_1 是 d 的倍数(d = gcd (a, b) = gcd(a_1, a_2)) m2m1dd=gcd(a,b)=gcd(a1,a2)

k 1 先 随 着 d 扩 大 到 m 2 − m 1 , 即 k 1 × m 2 − m 1 d k1先随着d扩大到m_2 - m_1,即 k1 \times \frac{m_2-m_1}{d} k1dm2m1,k1×dm2m1
解 出 k 1 的 通 解 为 k 1 = k 1 + a 2 d × k k , k k 为 整 数 解出 k_1 的通解为 k_1 = k_1 + \frac{a_2}{d} \times kk,kk 为整数 k1k1=k1+da2×kk,kk
所 求 x = a i × k i + m i = a 1 × k 1 + m 1 , 所求 x = a_i \times k_i + m_i = a_1\times k_1 + m_1, x=ai×ki+mi=a1×k1+m1,
通 解 为 x = a 1 ∗ k 1 + m 1 + a 1 ∗ a 2 d × k k , 通解为 x =a_1 *k_1 + m_1 + \frac{a_1*a_2}{d} \times kk, x=a1k1+m1+da1a2×kk
( a 1 、 m 1 给 出 , k 1 求 出 , k k 未 知 ( 由 于 k 1 有 题 解 所 以 有 k k ) ) (a_1、m_1给出,k_1求出,kk未知(由于k_1有题解所以有kk)) a1m1k1kk(k1kk)

要 使 得 x 为 最 小 非 负 整 数 , 那 么 k 1 要 小 , 且 保 证 为 非 负 整 数 , 要使得x为最小非负整数, 那么k1要小,且保证为非负整数, 使x,k1
即 k 1 = ( k 1 % a b s ( a 2 d ) + a b s ( a 2 d ) ) % a b s ( a 2 d ) 即 k1 = (k1 \%abs(\frac{a_2}{d}) +abs(\frac{a_2}{d}) ) \% abs(\frac{a_2}{d}) k1=(k1%abs(da2)+abs(da2))%abs(da2)

概括一下:(思路)
有 n 个 等 式 , 先 任 意 取 两 个 , 然 后 算 出 新 的 等 式 , 看 成 一 个 , 有n个等式,先任意取两个,然后算出新的等式,看成一个, n
再 与 后 面 的 新 的 式 子 , 即 x 相 等 , 前 两 个 等 式 化 成 的 等 式 再与后面的新的式子,即x相等,前两个等式化成的等式 x
x = a 1 ∗ k 1 + m 1 + a 1 ∗ a 2 d × k k 应 该 写 成 x = a i × k i + m i 的 格 式 x = a_1 *k_1 + m_1 + \frac{a_1*a_2}{d} \times kk 应该写成 x = a_i \times k_i + m_i的格式 x=a1k1+m1+da1a2×kkx=ai×ki+mi
在 上 面 的 式 子 中 , 只 有 k k 是 未 知 数 , 在上面的式子中,只有kk是未知数, kk
所 以 写 成 x = a 1 ∗ a 2 d × k k + ( a 1 ∗ k 1 + m 1 ) 所以写成x = \frac{a_1*a_2}{d} \times kk +( a_1 *k_1 + m_1 ) x=da1a2×kk+(a1k1+m1)
该 式 子 为 两 个 式 子 合 并 后 的 式 子 , 由 此 与 新 的 式 子 联 立 求 解 该式子为两个式子合并后的式子,由此与新的式子联立求解

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 7;
const int MAX = 1e5 + 10;
int a[MAX];
int m[MAX];

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;
}

int main() {
   int n;
   scanf("%d", &n);
   ll a1, m1, a2, m2;
   scanf("%lld%lld", &a1, &m1);
   bool flag = 1;
   ll x = 0;
   for(int i = 1; i < n; i++) {
       scanf("%lld%lld", &a2, &m2);
       ll k1, k2;
       ll d = exgcd(a1, -a2, k1, k2);
       if((m2 - m1) % d != 0) { flag = 0; }
       ll k11 = k1 * (m2 - m1) / d ;
       k1 = (k11 % abs(a2 / d) + abs(a2 / d)) % abs(a2 / d);
       x = a1 * k1 + m1;
       m1 = a1 * k1 + m1;
       a1 = abs(a1 / d * a2);
   }
   if(flag == 0) printf("-1\n");
   else printf("%lld\n", x);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值