exCRT 浅析
exCRT
处理 CRT 中 \(a_i\) 不互质的情况。
一般使用 exCRT 毕竟其又好想又好写。
exCRT 的核心在于维护一个同余方程,并将同余方程不断合并。
假设现在合并了前 \(i-1\) 个方程,不妨设
现在要 \(ans'\) 同时满足两个方程
两式相减有
这是一个同余方程,假设其解为
\(k=y + jp,j \in \Z\)
回代 \(ans'=ans_0+(y+jp)m=(ans_0+ym)+j \cdot pm\)
故 \(ans_0'=ans_0+ym,m'=m \cdot p,ans'=ans_0'+k \cdot m'\)
发现又回到了原来的形式,合并完成。
这个解系满足 \(ans'=(ans_0+ym)+j \cdot pm=ans_0 \pmod m\)
同时也满足第 \(i\) 个方程 \(ans'=ans_0+k \cdot m=b_i+k_1 \cdot a_i\)
接下来证明这样不会漏解
引理 : 两个同余方程在 \(lcm(a_1,a_2)\) 内有唯一解。
证明 : 反证法。
假设存在两个不同的解 \(0 \le x,y <lcm(a_1,a_2)\)
不妨设 \(x >y\)
则
换句话说
则有
由于 \(x-y <lcm(a_1,a_2)\)
所以 \(x-y=0 ,x=y\) 不符题意。
证毕。
考虑 \(m'=pm\)
因此不会漏解。
在写代码时,直接取 \(m'=lcm(m,a_i)\) 即可。
P4777 【模板】扩展中国剩余定理(EXCRT)
Code:
typedef long long LL;
LL muler(LL x,LL k,LL MOD)
{
LL res=0; k=(k%MOD+MOD)%MOD; x=(x%MOD+MOD)%MOD;
while(k) {
if(k&1) res=(res+x)%MOD;
x=(x+x)%MOD; k>>=1;
}
return res%MOD;
}
LL exgcd(LL a,LL b,LL& x,LL& y)
{
if(b==0) {
x=1; y=0;
return a;
}
LL z=exgcd(b,a%b,y,x);
y-=a/b*x;
return z;
}
LL excrt(int n,LL b[],LL a[])
{
for(int i=1;i<=n;i++) b[i]%=a[i]; // 先把 b[i] mod a[i] 否则 n=1 会错。
LL m=a[1],ans=b[1]; // 维护方程的解系为 {ans} = ans0 + k*m
for(int i=2;i<=n;i++) { // 尝试把第 i 个方程加入解系。
LL y,z,d=exgcd(m,a[i],y,z);
if((b[i]-ans)%d!=0) return -1; // 无法合并同余方程 --> 没有合法解
y=muler(y,(b[i]-ans)/d,a[i]/d); // 同余方程的最小正整数解。
ans+=y*m;
m=m/d*a[i]; // m = lcm{a[1]...a[i]} , 不要通过同余方程,这样就很方便,注意先除后乘。
ans=(ans%m+m)%m; // 让 ans 为最小正整数。
}
return ans;
}
关于标准形式和一般形式的转化。
$x =b_i \pmod {a_i} $ 是标准形式。
\(c_ix=b_i \pmod {a_i}\) 是一般形式。
一般形式不可直接求解,得先 \(\to\) 标准。
考虑先分别求解每一个 \(c_ix=b_i \pmod {a_i}\) ,由于 \(\gcd(c_i,a_i)\) 不一定为 \(1\) ,所以 \(c_i\) 不一定移得过去。
直接求解 \(c_ix+a_ik=b_i\),注意 \(x\) 的解集可以写成
这是标准形式,对新的方程组求解即可。
若单个方程都没有解,那么总的也没有解。