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

>Link

luogu P4777


>Description

求解一元线性同余方程组 { x ≡ b 1 ( m o d a 1 ) . . . . . . x ≡ b n ( m o d a n ) \left\{\begin{matrix}x\equiv b_1(mod a_1) \\ ...... \\ x\equiv b_n(mod a_n) \end{matrix}\right. xb1(moda1)......xbn(modan)
不保证 a a a两两互质


>解题思路

由于模数不保证两两互质,所以我们就不能用中国剩余定理的方法exgcd了
要用扩展中国剩余定理

参考自:建议看看这个巨爷的笔记QAQ,这里做个总结
我们先考虑两个式子 { x ≡ b 1 ( m o d a 1 ) x ≡ b 2 ( m o d a 2 ) \left\{\begin{matrix}x\equiv b_1(mod a_1) \\ x\equiv b_2(mod a_2) \end{matrix}\right. {xb1(moda1)xb2(moda2)
可以转换成 { x = b 1 + a 1 ∗ k 1 x = b 2 + a 2 ∗ k 2 \left\{\begin{matrix}x= b_1+a_1*k_1 \\ x=b_2+a_2 * k_2 \end{matrix}\right. {x=b1+a1k1x=b2+a2k2
联立得 b 1 + a 1 ∗ k 1 = b 2 + a 2 ∗ k 2 b_1+a_1*k_1=b_2+a_2 * k_2 b1+a1k1=b2+a2k2
移项得 a 1 ∗ k 1 − a 2 ∗ k 2 = b 2 − b 1 a_1*k_1-a_2 * k_2=b_2-b_1 a1k1a2k2=b2b1
这个式子就可以用exgcd来解决了,但是得满足 g c d ( a 1 , a 2 ) ∣ b 2 − b 1 gcd(a_1,a_2)|b_2-b_1 gcd(a1,a2)b2b1这个前提(回顾下exgcd: a 1 ∗ k 1 − a 2 ∗ k 2 = g c d ( a 1 , a 2 ) a_1*k_1-a_2 * k_2=gcd(a_1,a_2) a1k1a2k2=gcd(a1,a2)),最后求出来两边再乘上 ( b 2 − b 1 ) / g c d ( a 1 , a 2 ) (b_2-b_1)/gcd(a_1,a_2) (b2b1)/gcd(a1,a2)就行了

我们设用exgcd求出来的其中两个解为 K 1 K_1 K1 K 2 K_2 K2,即 a 1 ∗ K 1 − a 2 ∗ K 2 = g c d ( a 1 , a 2 ) a_1*K_1-a_2 * K_2=gcd(a_1,a_2) a1K1a2K2=gcd(a1,a2)
按照前面说的,两边乘上 ( b 2 − b 1 ) g c d ( a 1 , a 2 ) \frac{(b_2-b_1)}{gcd(a_1,a_2)} gcd(a1,a2)(b2b1),得到 k 1 = K 1 ∗ ( b 2 − b 1 ) g c d ( a 1 , a 2 ) k_1=K_1*\frac{(b_2-b_1)}{gcd(a_1,a_2)} k1=K1gcd(a1,a2)(b2b1) k 2 = K 2 ∗ ( b 2 − b 1 ) g c d ( a 1 , a 2 ) k_2=K_2*\frac{(b_2-b_1)}{gcd(a_1,a_2)} k2=K2gcd(a1,a2)(b2b1)
现在我们就可以求出一个 x x x

可是显然不只有一个 x x x
设求出来的两个解为 x 0 x_0 x0 x 1 x_1 x1,满足 x 0 < x 1 x_0<x_1 x0<x1
两个解都满足同余方程,所以 { x 0 ≡ b 1 ( m o d a 1 ) x 1 ≡ b 1 ( m o d a 1 ) \left\{\begin{matrix}x_0\equiv b_1(mod a_1) \\ x_1\equiv b_1(mod a_1) \end{matrix}\right. {x0b1(moda1)x1b1(moda1) { x 0 ≡ b 2 ( m o d a 2 ) x 1 ≡ b 2 ( m o d a 2 ) \left\{\begin{matrix}x_0\equiv b_2(mod a_2) \\ x_1\equiv b_2(mod a_2) \end{matrix}\right. {x0b2(moda2)x1b2(moda2)
设存在 s 1 s_1 s1 s 2 s_2 s2,使得 x 1 = x 0 + a 1 ∗ s 1 x_1= x_0+a_1*s_1 x1=x0+a1s1 x 1 = x 0 + a 2 ∗ s 2 x_1= x_0+a_2*s_2 x1=x0+a2s2
移项得 x 1 − x 0 = a 1 ∗ s 1 x_1- x_0=a_1*s_1 x1x0=a1s1 x 1 − x 0 = a 2 ∗ s 2 x_1- x_0=a_2*s_2 x1x0=a2s2,所以 a 1 ∗ s 1 = a 2 ∗ s 2 a_1*s_1=a_2*s_2 a1s1=a2s2
d 1 = a 1 g c d ( a 1 , a 2 ) d_1=\frac{a_1}{gcd(a_1,a_2)} d1=gcd(a1,a2)a1 d 2 = a 2 g c d ( a 1 , a 2 ) d_2=\frac{a_2}{gcd(a_1,a_2)} d2=gcd(a1,a2)a2(我们知道 g c d ( d 1 , d 2 ) = 1 gcd(d_1,d_2)=1 gcd(d1,d2)=1),得 d 1 ∗ g c d ( a 1 , a 2 ) ∗ s 1 = d 2 ∗ g c d ( a 1 , a 2 ) ∗ s 2 d_1*gcd(a_1,a_2)*s_1=d_2*gcd(a_1,a_2)*s_2 d1gcd(a1,a2)s1=d2gcd(a1,a2)s2,即 d 1 ∗ s 1 = d 2 ∗ s 2 d_1*s_1=d_2*s_2 d1s1=d2s2
所以我们得到 d 1 ∣ s 2 d_1|s_2 d1s2
d 1 ∗ d 2 ∣ s 2 ∗ d 2 d_1 * d_2|s_2 * d_2 d1d2s2d2
d 1 ∗ d 2 ∗ g c d ( a 1 , a 2 ) ∣ s 2 ∗ d 2 ∗ g c d ( a 1 , a 2 ) d_1 * d_2 *gcd(a_1,a_2)|s_2 * d_2*gcd(a_1,a_2) d1d2gcd(a1,a2)s2d2gcd(a1,a2)
l c m ( a 1 , a 2 ) ∣ x 1 − x 0 lcm(a_1,a_2)|x_1- x_0 lcm(a1,a2)x1x0
所以 x 1 − x 0 x_1-x_0 x1x0一定是 l c m ( a 1 , a 2 ) lcm(a_1,a_2) lcm(a1,a2)的倍数!!!求出一个 x x x,其它加上任意倍 l c m ( a 1 , a 2 ) lcm(a_1,a_2) lcm(a1,a2)就行了

so

M M M表示当前所有 a a a l c m lcm lcm X X X表示当前解
枚举到当前数,解表示为 X + t ∗ M X+t*M X+tM
满足 X + t ∗ M ≡ b i ( m o d a i ) X+t*M\equiv b_i(mod a_i) X+tMbi(modai),移项得 t ∗ M ≡ b i − X ( m o d a i ) t*M\equiv b_i-X(mod a_i) tMbiX(modai)


>代码

//还是不是很懂 需要再看一下QAQ

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define LL long long
using namespace std;

int n;
LL a[N], b[N], M, ans;

LL mul (LL aa, LL bb, LL Mod)
{
	LL ret = 0;
	aa %= Mod;
	for (; bb; bb >>= 1, aa = (aa + aa) % Mod)
	  if (bb & 1) ret = (ret + aa) % Mod;
	return ret;
}
LL ex_gcd (LL aa, LL bb, LL &x, LL &y)
{
	if (!bb) {x = 1, y = 0; return aa;}
	LL X = x, Y = y;
	LL ret = ex_gcd (bb, aa % bb, X, Y);
	x = Y;
	y = X - (aa / bb) * Y;
	return ret;
}

int main()
{
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++)
	  scanf ("%lld%lld", &a[i], &b[i]);
	M = a[1], ans = b[1];
	for (int i = 2; i <= n; i++)
	{
		LL x = 0, y = 0;
		LL g = ex_gcd (M, a[i], x, y);
		//if ((b[i] - ans) % g != 0) nosolution~
		/*x = x * ((b[i] - ans) / g);
		LL t = a[i] / g;
		x = (x % t + t) % t;*/
		LL t = (b[i] - ans % a[i] + a[i]) % a[i];
		x = mul (x, t / g, a[i] / g);
		ans = ans + x * M;
		M = M * (a[i] / g);
		ans = (ans % M + M) % M;
	}
	ans = (ans % M + M) % M;
	printf ("%lld", ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值