模板 - 扩展中国剩余定理

匿名 (未验证) 提交于 2019-12-02 23:55:01

解k个线性同余方程构成的线性同余方程组,每个方程形如: $x_i = c_i mod m_i$ ,假如有解输出最小非负整数解,否则输出-1。

可能在模数比较大的时候会溢出的版本,方法是直接对两个方程强行合并。

#include<bits/stdc++.h> using namespace std; typedef long long ll;  const int MAXK = 100005;  void exgcd(ll a, ll b, ll &x, ll &y) {     if(!b)         x = 1, y = 0;     else         exgcd(b, a % b, y, x), y -= a / b * x; }  ll inv(ll a, ll b) {     ll x = 0, y = 0;     exgcd(a, b, x, y);     x = (x % b + b) % b;     if(!x)         x += b;     return x; }  int k; ll c[MAXK], m[MAXK];  //解k个线性同余方程构成的方程组, xi = ci mod mi ,假如有解,返回最小非负整数解,否则返回-1 ll exCRT(int k) {     ll c1, c2, m1, m2, t;     for(int i = 2; i <= k; ++i) {         m1 = m[i - 1], m2 = m[i], c1 = c[i - 1], c2 = c[i];         t = __gcd(m1, m2);         if((c2 - c1) % t != 0)             return -1;         m[i] = m1 * m2 / t;         c[i] = inv(m1 / t, m2 / t) * ((c2 - c1) / t) % (m2 / t) * m1 + c1;         c[i] = (c[i] % m[i] + m[i]) % m[i];     }     return c[k]; }  //解k个线性同余方程构成的方程组, xi = ci mod mi ,假如有解,返回最小非负整数解,否则返回-1 int main() { #ifdef Inko     freopen("Inko.in", "r", stdin); #endif // Inko     while(~scanf("%d", &k)) {         for(int i = 1; i <= k; ++i)             scanf("%lld%lld", &m[i], &c[i]);         printf("%lld\n", exCRT(k));     } }

有时候题目的确会溢出,这个时候要选择带有大数取模的Java(注意BigInteger是传值而不是传引用的)。但有时候可以把每个同余方程分解成几个小的。

来源: https://www.cnblogs.com/Inko/p/11380750.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!