中国剩余定理 CRT

推导

给定\(n\)个同余方程

\[\left\{
\begin{aligned}
x &\equiv a_1 \pmod{m_1} \\
x &\equiv a_2 \pmod{m_2} \\
&... \\
x &\equiv a_n \pmod{m_n}
\end{aligned}
\right.
\]

\(m_1, m_2 , ... , m_n\)两两互质

令\(M = \prod_{i=1}^{n} m_i\),求\(x \mod M\)

解决该问题的方法是构造。

我们假定最终答案的形式是一个\(n\)个项的和式,对每个同余方程的构造反应在对应项的系数上。

如果要对每一个项分别构造,就要求为每一项乘上一个合适的数,使得每项构造的系数对其他方程的结果没有影响。

容易想到构造

\[M_i = \frac{M}{m_i}
\]

显然该数仅在模\(m_i\)时不为\(0\),于是改变该项的系数将不会对其他方程造成影响。

现在我们希望该项模\(m_i\)意义下是\(a_i\),但上一次的构造残留下了一个\(M_i\)。简单粗暴的乘上\(M_i\)在模\(m_i\)意义下的逆元\(inv_{m_i}(M_i)\),让该项在模\(m_i\)意义下变为\(1\),然后乘上\(a_i\)就构造出来了。

综上,答案为

\[\sum_{i=1}^{n} M_i inv_{m_i}(M_i) a_i \mod{M}
\]

模数互质条件保证了\(M_i\)非\(0\),保证了\(inv_{m_i}(M_i)\)的存在。

实现

大部分题的所有\(m_i\)都是质数,求逆元\(QPow\)即可。

对于一般的情况,上exgcd就行。

板题:洛谷P1495 曹冲养猪

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll; namespace ExGcd{
ll x,y;
ll ExGcd(ll a,ll b){
ll ans;
if(a%b==0){
x=0;y=1;ans=b;
}else{
ans=ExGcd(b,a%b);
ll x1=x,y1=y;
x=y1;y=x1-a/b*y1;
}
return ans;
}
bool SolveEqu(ll a,ll b,ll c){
ll d=ExGcd(a,b);
if(c%d!=0) return 0;
x*=c/d;y*=c/d;
x=(x%b+b)%b;
y=(c-a*x)/b;
return 1;
}
}
ll Inv(ll a,ll m){
ExGcd::SolveEqu(a,m,1);
return ExGcd::x;
} const ll CRTN=20;
namespace CRT{
ll N;
ll m[CRTN],a[CRTN];
ll Sol(){
ll ans=0,M=1;
for(ll i=1;i<=N;i++) M*=m[i];
for(ll i=1;i<=N;i++){
ll Mi=M/m[i];
ans=(ans+Mi*Inv(Mi,m[i])*a[i])%M;
}
return ans;
}
}
int main(){
using namespace CRT;
scanf("%lld",&N);
for(ll i=1;i<=N;i++)
scanf("%lld%lld",&m[i],&a[i]);
printf("%lld",Sol());
return 0;
}

拓展中国剩余定理 ExCRT

ExCRT和CRT并没有什么关系,正如ExLucas和Lucas也没什么关系

其实从纯推理的角度来看,ExCRT可能还要好想一点(

推导

问题同CRT,但是模数是任意的,并不要求互质。

这时,我们就不能保证存在逆元了。那么如何解决该问题呢?

考虑如何合并两个方程。如果我们找到了合并的方法,就能如法炮制将\(n\)个方程依次合并起来,得到答案。

\[\left\{
\begin{aligned}
x &\equiv a_1 \pmod{m_1} \\
x &\equiv a_2 \pmod{m_2}
\end{aligned}
\right.
\]

去掉同余,化为不定方程

\[\left\{
\begin{aligned}
x &= m_1 y_1 + a_1 \\
x &= m_2 y_2 + a_2
\end{aligned}
\right.
\]

于是得到

\[m_1 y_1 + a_1 = m_2 y_2 + a_2
\]

只要找到一组满足该式的\(y_1\)和\(y_2\),就能反算出\(x\),实现合并。

而我们得到的是一个二元一次的不定方程,可以用exgcd求解。

化为标准式

\[m_1 y_1 - m_2 y_2 = a_2 - a_1
\]

解就是了。如果没有解,说明同余方程组无解。

于是最后化得的合并式为

\[x \equiv m_1 y_1 + a_1 \pmod{lcm(m_1,m_2)}
\]

实现

唯一需要注意的地方是,本来解方程应该解\((m_1,-m_2,a_2-a_1)\),但ExGCD不好处理负数,所以把\(m_2\)改成了\(m_1\)。因为我们并不需要用到\(y_2\),所以显然是没有影响的。

板题:poj2891 Strange Way to Express Integers or 洛谷P4777 扩展中国剩余定理(EXCRT)

会被卡乘法爆ll,懒得改

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll; namespace ExGcd{
ll x,y;
ll ExGcd(ll a,ll b){
ll ans;
if(a%b==0){
x=0;y=1;ans=b;
}else{
ans=ExGcd(b,a%b);
ll x1=x,y1=y;
x=y1;y=x1-a/b*y1;
}
return ans;
}
bool SolveEqu(ll a,ll b,ll c){
ll d=ExGcd(a,b);
if(c%d!=0) return 0;
x*=c/d;y*=c/d;
x=(x%b+b)%b;
y=(c-a*x)/b;
return 1;
}
}
ll Gcd(ll a,ll b){
if(a%b==0) return b;
return Gcd(b,a%b);
}
namespace ExCRT{
ll a1,m1;
void Init(){
a1=0;m1=1;
}
void Expand(ll a2,ll m2){
ExGcd::SolveEqu(m1,m2,a2-a1);
ll y1=ExGcd::x;
ll mn=m1*m2/Gcd(m1,m2);
a1=(m1*y1+a1)%mn;
m1=mn;
}
}
int main(){
ll N;scanf("%lld",&N);
ExCRT::Init();
for(ll i=1;i<=N;i++){
ll a,m;scanf("%lld%lld",&m,&a);
ExCRT::Expand(a,m);
}
printf("%lld",ExCRT::a1);
return 0;
}

2019/12/21

中国剩余定理(CRT)及其拓展(ExCRT)的更多相关文章

  1. 中国剩余定理(CRT)及其扩展(EXCRT)详解

    问题背景   孙子定理是中国古代求解一次同余式方程组的方法.是数论中一个重要定理.又称中国余数定理.一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作<孙子算经>卷下第 ...

  2. 中国剩余定理(CRT) & 扩展中国剩余定理(ExCRT)总结

    中国剩余定理(CRT) & 扩展中国剩余定理(ExCRT)总结 标签:数学方法--数论 阅读体验:https://zybuluo.com/Junlier/note/1300035 前置浅讲 前 ...

  3. 中国剩余定理 CRT

    中国剩余定理 CRT 正常版本CRT 要解的是一个很容易的东西 \[ \begin{aligned} x\equiv a_1(mod\ m_1)\\ x\equiv a_2(mod\ m_2)\\ . ...

  4. 扩展GCD 中国剩余定理(CRT) 乘法逆元模版

    extend_gcd: 已知 a,b (a>=0,b>=0) 求一组解 (x,y) 使得 (x,y)满足 gcd(a,b) = ax+by 以下代码中d = gcd(a,b).顺便求出gc ...

  5. 学习笔记:中国剩余定理(CRT)

    引入 常想起在空间里见过的一些智力题,这个题你见过吗: 一堆苹果,\(3\)个\(3\)个地取剩\(1\)个,\(5\)个\(5\)个地取剩\(1\)个,\(7\)个\(7\)个地取剩\(2\)个,苹 ...

  6. 拓展中国剩余定理(exCRT)摘要

    清除一个误区 虽然中国剩余定理和拓展中国剩余定理只差两个字,但他俩的解法相差十万八千里,所以会不会CRT无所谓 用途 求类似$$\begin{cases}x \equiv b_{1}\pmod{a_{ ...

  7. 欧几里得(辗转相除gcd)、扩欧(exgcd)、中国剩余定理(crt)、扩展中国剩余定理(excrt)简要介绍

    1.欧几里得算法(辗转相除法) 直接上gcd和lcm代码. int gcd(int x,int y){ ?x:gcd(y,x%y); } int lcm(int x,int y){ return x* ...

  8. 中国剩余定理及其拓展 CRT&EXGCD

    中国剩余定理,又叫孙子定理. 作为一个梗广为流传.其实它的学名叫中国单身狗定理. 中国剩余定理 中国剩余定理是来干什么用的呢? 其实就是用来解同余方程组的.那么什么又是同余方程组呢. 顾名思义就是n个 ...

  9. CRT&EXCRT 中国剩余定理及其扩展

    前言: 中国剩余定理又名孙子定理.因孙子二字歧义,常以段子形式广泛流传. 中国剩余定理并不是很好理解,我也理解了很多次. CRT 中国剩余定理 中国剩余定理,就是一个解同余方程组的算法. 求满足n个条 ...

随机推荐

  1. vue监听移动设备的返回事件

    在公共方法文件common.js中实现一个存储当前历史记录的方法 common.js // 存储当前历史记录点,实现控制手机物理返回键的按钮事件 var pushHistory = function ...

  2. 搭建wordPress遇到无法连接数据库的问题

    在确认了数据库用户,密码,地址都没有错的情况下,仍然出现无法连接数据库的问题,以至无法安装wordpress 我的wordpress:4.8.1-zh_CN 解决办法: 1.更改php的版本(我的改为 ...

  3. scikit-learn_cookbook1: 高性能机器学习-NumPy

    源码下载 在本章主要内容: NumPy基础知识 加载iris数据集 查看iris数据集 用pandas查看iris数据集 用NumPy和matplotlib绘图 最小机器学习配方 - SVM分类 介绍 ...

  4. Spring Boot整合Mybatis报错InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider

    Spring Boot整合Mybatis时一直报错 后来发现原来主配置类上的MapperScan导错了包 由于我使用了通用Mapper,所以应该导入通用mapper这个包

  5. adb查看Android app包名

    1. 确保电脑已经安装了adb.exe文件 2. 使用USB连接你的手机到电脑上,输入下图所示的命令后按下回车键:adb devices 3. 使用手机打开某个应用程序 4.回到命令号窗口,输入代码如 ...

  6. python基础-网络编程part02

    TCP协议 TCP是传输控制协议,建立双向通道. 三次握手,建立连接 客户端向服务端发送建立连接的请求 服务端接收请求返回确认信息给客户端,并向客户端发送建立连接的请求 客户端接收请求返回确认信息给服 ...

  7. Java基础部分(11~20)

    11."=="和 equals 方法究竟有什么区别? (单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚) ==操作符专门用来比较两 ...

  8. 移动端touch滑动事件监听

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. for循环、while循环、break跳出循环、continue结束本次循环、exit退出整个脚本

    7月13日任务 20.10 for循环20.11/20.12 while循环20.13 break跳出循环20.14 continue结束本次循环20.15 exit退出整个脚本扩展select用法 ...

  10. Spring Boot应用启动的三种方式

    Spring Boot应用HelloWorld的三种启动方式: 项目的创建可以在http://start.spring.io/网站中进行项目的创建. 首先项目结构: 1.  通过main方法的形式启动 ...