题解 P4777 【【模板】扩展中国剩余定理(EXCRT)】

sumijie

2018-09-22 20:47:19

Solution

## 对于一组同余方程 $\begin{cases} x \equiv a_1\ ({\rm mod}\ n_1) \\ x\equiv a_2\ ({\rm mod}\ n_2) \\ ... \\ x \equiv a_n\ ({\rm mod}\ n_n)\end{cases} $ **对于第一个和第二个式子** **则有:** $x = a_1 + k_1*n_1$ $x = a_2 + k_2*n_2$ **就有:** $a_1 + k_1*n_1 = a_2 + k_2*n_2$ $k_1*n_1 - k_2*n_2 = a_2 - a_1$ **故我们设 $d = a_2 - a_1$** **再变化一下形式就有:** $k_1*n_1 + (-k_2)*n_2 = d$ **令 $g = gcd(n_1,n_2)$** **这样我们就可以通过exgcd来求出一组解 $x_1,y_1$** **满足 $x_1*n_1 + y_2*n_2 = g$** **故:** $x_1*d/g *n_1 + y_2*d/g*n_2 = g*d/g$ **则:** $k_1 = x_1*d/g,k_2 = y_1*d/g$ **从而得到一组通解** $k_1 = k_1 + n2/g*T$ $k_2 = k_2 - n1/g*T$ **要使所求得的解最小且为正整数则可以根据 $k_1$ 的通解形式求得** $ k_1 = (k_1\%(n_2/g) + n_2/g)\%(n_2/g) $ **再带入 $x = a_1 + k_1*n_1$ 得到 $x$ ** **令 $A$ 为合并后的 $a$ , $N$ 为合并后的 $n$** **所以$N = lcm(n_1,n_2) = n_1 * n_2 / g$** **根据$x \equiv A\ ({\rm mod}\ N)$ 且 $x$ 是满足该式子最小的值** **得到:** $A = x$ # 欢迎来卡 ```cpp #include<iostream> typedef __int128 ll; using namespace std; void exgcd(ll a,ll b,ll &g,ll &x,ll &y) { if (b == 0) { g = a; x = 1; y = 0; return; } exgcd(b,a%b,g,y,x); y-=(a/b)*x; } bool flag = false; ll a1,a2,n1,n2; ll abs(ll x) { return x>0?x:-x; } void china() { ll d = a2 - a1; ll g,x,y; exgcd(n1,n2,g,x,y); if (d % g == 0) { x = ((x*d/g)%(n2/g)+(n2/g))%(n2/g); a1 = x*n1 + a1; n1 = (n1*n2)/g; } else flag = true; } int n; long long as[100001]; long long ns[100001]; ll realchina() { a1 = as[0]; n1 = ns[0]; for (ll i = 1;i<n;i++) { a2 = as[i]; n2 = ns[i]; china(); if (flag) return -1; } return a1; } int main() { cin>>n; flag = false; for (ll i = 0;i<n;i++) cin>>ns[i]>>as[i]; cout<<(long long)realchina()<<endl; } ```