解决的问题:求一个最小正整数x。x满足条件 x % m[ ] = a[ ];
1 中国剩余定理只能解决m互质时;
2 扩展中国剩余定理可以解决的m不互质,但是可以m互质时用扩展中国剩余定理会慢。
中国剩余定理的证明我说一下把,扩展的不熟练怕误人子弟。
首先说一下值的意思。
lcm = m1*m2*m3..... Mi = lcm/mi
证明: ①mi和其他数是互质的和其他值的乘积同样互质 gcd(Mi, mi) == 1
②由扩展欧几里得性质(ax+by=c 当且仅当c%gcd(x,y) = 0) Mi*x + mi*y = 1
③两边模mi,-> Mi*x % mi = 1, 令ei = Mi*x
即ei ≡ 0(mod mj), j != i
ei ≡ 1(mod mj), j = i
④故一个解是e1*a1 + e2*a2 + ....... + en*an
中国剩余定理模板 洛谷模板题https://www.luogu.org/problem/P3868
求x:x % m[] = a[]; 并且m数组是互质的。①适用于a,m为非负整数,如果又a有负数,先转化成正,下边有写。②乘时可能爆ll,有时需要快速乘。 ll a[100], m[100]; ll exgcd(ll a, ll b, ll &x, ll &y){ //扩展欧几里得 if(!b){ x = 1; y = 0; return a; } ll gcd = exgcd(b, a%b, y, x); y -= a/b * x; return gcd; } ll chinese_lest(int n){ ll lcm = 1, ans = 0, x, y; for(int i = 1; i <= n; i++) lcm*=m[i]; for(int i = 1; i <= n; i++){ ll mi = lcm/m[i]; ll gcd = exgcd(m[i], mi, x, y); ans = (ans + y*mi*a[i])%lcm; } return (lcm + ans)%lcm; } int main(){ int n; cin >> n; for(int i = 1; i <= n; i++) cin >> a[i]; for(int i = 1; i <= n; i++) cin >> m[i]; //for(int i = 1; i <= n; i++) a[i] = (a[i]+m[i])%m[i]; //有负数的情况 cout << chinese_lest(n) << endl; }
扩展中国剩余定理模板 洛谷模板题https://www.luogu.org/problem/P4777
#include <cstdio> #include <iostream> #define ll long long using namespace std; //求x:x % m[] = a[]; m数组不互质,无解输出-1. ll a[100005], m[100005]; ll exgcd(ll a, ll b, ll &x, ll &y){ if(!b){ x = 1; y = 0; return a; } ll gcd = exgcd(b, a%b, y, x); y -= a/b * x; return gcd; } ll qmul(ll a, ll b, ll mod){ ll tot = 0; while(b){ if(b&1) tot = (tot+a)%mod; a = (a+a)%mod; b>>=1; } return tot; } ll exchinese_lest(int n){ ll x, y; ll M = m[1], ans = a[1]; for(int i = 2; i <= n; i++){ ll A = M, b = m[i], c = (a[i] - ans % b + b) % b; ll gcd = exgcd(A, b, x, y), bg = b / gcd; if(c % gcd != 0) return -1; x = qmul(x, c / gcd, bg); ans += x * M; M *= bg; ans = (ans % M + M) % M; } return (ans % M + M) % M; } int main(){ int n; cin >> n; for(int i = 1; i <= n; i++) cin >> a[i]; for(int i = 1; i <= n; i++) cin >> m[i]; cout << exchinese_lest(n) << endl; return 0; }