P4777 【模板】扩展中国剩余定理(EXCRT)&& EXCRT
EXCRT
不保证模数互质
\[\begin{cases} x \equiv b_1\ ({\rm mod}\ a_1) \\ x\equiv b_2\ ({\rm mod}\ a_2) \\ ... \\ x \equiv b_n\ ({\rm mod}\ a_n)\end{cases}
\]
CRT戳这里
来一手数学归纳法
设已经求出前 \(k - 1\) 组的一个解 \(q\)
设 \(M = \prod_{i = 1}^{k - 1}a_{i}\)
我们知道前 \(k - 1\) 组的通解为 \(q + xM\)
现在考虑第 \(k\) 组方程
设存在一 \(x\) 满足
\[q + xM \equiv b_{k}\ (mod\ a_{k})
\]
移一下项
\[xM \equiv b_{k} - q\ (mod\ a_{k})
\]
于是很愉快的解一下同余方程即可
如此, 我们使用扩展欧几里得算法 \(n\) 次, 便求出了方程组的解
复杂度 \(O(n \log n)\)
P4777 【模板】扩展中国剩余定理(EXCRT)
题目描述
给定 n组非负整数 a_i, b_i 求解关于 x的方程组的最小非负整数解。
Solution
注意中间运算会爆 \(longlong\) ,使用龟速乘
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const LL maxn = 200019;
LL num, a[maxn], b[maxn];
LL x, y;
LL Q_mul(LL a, LL b, LL mod){
	LL ans = 0;
	while(b){
		if(b & 1)ans = (ans + a) % mod;
		a = (a + a) % mod;
		b >>= 1;
		}
	return ans % mod;
	}
LL exgcd(LL a, LL b, LL &x, LL &y){
	if(!b){x = 1, y = 0;return a;}
	LL d = exgcd(b, a % b, x, y);
	LL temp = x;x = y;y = temp - (a / b) * y;
	return d;
	}
LL EXCRT(){
	LL M = a[1], ans = b[1];
	REP(i, 2, num){
		LL A = M, B = a[i], C = ((b[i] - ans) % B + B) % B;
		LL d = exgcd(A, B, x, y);
		if(C % d != 0) return -1;
		x = Q_mul(x, C / d, B / d);
		ans += x * M;
		M *= B / d;
		ans = (ans % M + M) % M;
		}
	return (ans % M + M) % M;
	}
int main(){
	num = RD();
	REP(i, 1, num)a[i] = RD(), b[i] = RD();
	printf("%lld\n", EXCRT());
	return 0;
	}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号