中国剩余定理(CRT)

引出

        在《孙子算经》中有这样一个问题:

        “今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”

也就是说有如下的方程组:

\begin{cases} x\ mod\ 3\ =\ 2\\ x\ mod\ 5\ = \ 3\\ x\ mod\ 7\ = \ 2 \end{cases}  \Rightarrow \begin{cases} x\equiv 2\ (mod\ 3)\\ x\equiv 3\ (mod\ 5)\\ x\equiv 2\ (mod\ 7) \end{cases}     求该方程组的解

x_0为最小整数解:

则   x_0 = x + k*(lcm(3,5,7)) = (x_0\ mod\ 105+105)\ mod\ 105

令  x = 2x_1+3x_2+2x_3 ,且

\begin{cases} x_1 \ mod\ 3 = 1\\ x_1\ mod\ 5 = 0\\ x_1\ mod\ 7 = 0 \end{cases} \begin{cases} x_2 \ mod\ 3 = 0\\ x_2\ mod\ 5 = 1\\ x_2\ mod\ 7 = 0 \end{cases} \begin{cases} x_3 \ mod\ 3 = 0\\ x_3\ mod\ 5 = 0\\ x_3\ mod\ 7 = 1 \end{cases}

通过取模得0的几个式子可以得到其最小公倍数

x_1 = 35k,\ k=2 \rightarrow x_1\ mod\ 3 = 1\rightarrow x_1=70

x_2 = 21k,\ k=1 \rightarrow x_2\ mod\ 5 = 1\rightarrow x_2=21

x_3 = 15k,\ k=1 \rightarrow x_3\ mod\ 7 = 1\rightarrow x_3=15

上述均可化为  ak\equiv 1(mod\ b) 的形式求逆元

x = 2*70 + 3*21+2*15=233

x_0= (233\ mod\ 105+105)\ mod\ 105 = 23

中国剩余定理

用于求解以下式子,其中 b_i 两两互质:

\begin{cases} x \equiv a_1\ (mod\ b_1)\\ x \equiv a_2\ (mod\ b_2)\\ ......\\ x \equiv a_n\ (mod\ b_n) \end{cases}

过程:

计算所有 b 的乘积 B

对于第i个式子:

  • 前i-1个式子的解为ans
  • 计算 m_i = \frac{B}{b_i} 以及 m_i 在模 b_i 意义下的逆元 m_i^{-1}
  • 前i个式子的解为  ans +a_im_im_i^{-1}\ (mod\ B)

最终解为  x = \sum_{i=1}^{n}a_im_im_i^{-1}(mod\ B)

证明:

对于所有的 m_i ,必定有  \sum_{j=1}^{n}[i\neq j]  个 b_j 为 m_i 的因子,即  m_i\ \equiv 0\ (mod\ b_j)

反过来说对于 b_j 只有 m_j 不为其倍数

根据  x = \sum_{i=1}^{n}a_im_im_i^{-1}(mod\ B),则有  x\equiv \sum_{i=1}^{n}a_im_im_i^{-1}(mod\ b_j)

在 i\neq j 时 m_i 皆为 b_j 的倍数, 所以  x \equiv a_jm_jm_j^{-1}(mod\ b_j)

 m_j^{-1} 是 m_j 模 b_j 意义下的逆元,化简 x \equiv a_j(mod\ b_j),可证得同余方程组解的正确性

一般需要用到龟速乘来确保不会溢出:

long long CRT()
{
	long long ans = 0;
	long long m = 1;
	for(int i = 1;i <= n;i++)
	{
		m *= b[i];
	}
	for(int i = 1;i <= n;i++)
	{
		long long mi = m / b[i];
		exgcd(mi,b[i]);
		x = (x % b[i] + b[i]) % b[i];
		ans = (ans + slow_mul(mi,x*a[i],m) % m + m) % m;
	}
	return (ans % m + m) % m;
}

扩展中国剩余定理

同样对于以下式子,其中 b_i 不保证互质:

\begin{cases} x \equiv a_1\ (mod\ b_1)\\ x \equiv a_2\ (mod\ b_2)\\ ......\\ x \equiv a_n\ (mod\ b_n) \end{cases}

过程:

  • 对于前i-1个式子,假设已求得答案x_{i-1},对于第1个式子有 x_1 = a_1
  • 令 m = lcm(b_1...b_{i-1}) ,则前i-1个式子通解为 x_{i-1} + km
  • 第i个方程的解既要满足第i个方程也要满足前i-1个方程,则 x_i = x_{i-1} + km
  • 将该式代入第i个方程求解 x_{i-1}+km\equiv a_i\ (mod\ b_i)
  • 转化一下式子: km \equiv a_i-x_{i-1}\ (mod\ b_i) ,可以用exgcd求解k
  • 将解得的k带回 x_i = x_{i-1} + km 可得到前i个方程的解

重复该步骤即可求得n组方程的解x

long long EXCRT()
{
	long long res = a[1];
	long long m = b[1];
	for(int i = 2;i <= n;i++)
	{
		long long A = m;
		long long B = b[i];
		long long C = (a[i] - res + B) % B;
		exgcd(A,B);
		x = slow_mul(x,C/__gcd(A,B),B);
		res += x*m;
		m = lcm(m,B);
		res = (res%m + m) % m;
	}
	return res;
}

注意有些题目可能有无解的情况,判断exgcd有无解即可

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值