中国剩余定理例题
(其实和标题没啥关系,重点在于分析
题意
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),
取两个等式,x≡m1(mod a1)和x≡m2(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+m1和x=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×a1−k2×a2=m2−m1,
即
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)) 两式子有解,即m2−m1是d的倍数(d=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}
k1先随着d扩大到m2−m1,即k1×dm2−m1
解
出
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 为整数
解出k1的通解为k1=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=a1∗k1+m1+da1∗a2×kk,
(
a
1
、
m
1
给
出
,
k
1
求
出
,
k
k
未
知
(
由
于
k
1
有
题
解
所
以
有
k
k
)
)
(a_1、m_1给出,k_1求出,kk未知(由于k_1有题解所以有kk))
(a1、m1给出,k1求出,kk未知(由于k1有题解所以有kk))
要
使
得
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=a1∗k1+m1+da1∗a2×kk应该写成x=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=da1∗a2×kk+(a1∗k1+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);
}