引入

常想起在空间里见过的一些智力题,这个题你见过吗:

一堆苹果,\(3\)个\(3\)个地取剩\(1\)个,\(5\)个\(5\)个地取剩\(1\)个,\(7\)个\(7\)个地取剩\(2\)个,苹果最少有几个?

够焦头烂额的(雾

大力算可知至少有16个。

我们把它抽象成数学问题:

求满足

\[\begin{cases}x\equiv1\pmod{3}\\x\equiv1\pmod{5}\\x\equiv2\pmod{7}\end{cases}
\]

的最小正整数\(x\)。

感性地猜到有一个长为\(3×5×7=105\)的循环节,至于为啥,一会就知道了。

求解

(下面是老祖宗神奇的思维,别问我为什么)

构造方程组:

\[\begin{cases}x\equiv0\pmod{3}\\x\equiv0\pmod{5}\\x\equiv1\pmod{7}\end{cases}
\]

显然这里\(x\)可表示为\(15y(y\in Z)\),即:

\[15y\equiv1\pmod{7}
\]

可得(不就是乘法逆元吗?):

\[15y\equiv1\pmod{7} \xrightarrow{}y\equiv1\pmod{7}\xrightarrow{}y_{min}=1\xrightarrow{}x_{min}=15
\]

同理构造三个方程,解(\(x\))分别为:\(15,70,21\)。

再乘上余数即可(记得取模):

\[ans=15×2+70×1+21×1=121\equiv16\pmod{3×5×7=105}
\]

最后的答案即为同余号右边的数。

这样可以用代码实现:

题目链接:P1495 【模板】中国剩余定理(CRT)/曹冲养猪

\(Code\):

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int n;
ll a[15],b[15];
ll sum=1,now=1,ans=0,rt=1;
ll x,y;
inline void exgcd(ll a,ll b)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
ll t=x;
x=y;
y=t-a/b*y;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
for(int i=1;i<=n;i++) rt=rt*a[i];
for(int i=1;i<=n;i++)
{
sum=now=1;
for(int j=1;j<=n;j++) if(i!=j) now=now*a[j],sum=sum*a[j]%a[i];
exgcd(sum,a[i]);
x=(x%a[i]+a[i])%a[i];
ans=(ans+b[i]*x*now)%rt;
}
printf("%lld\n",ans);
return 0;
}

复杂度是\(O(n^2+nlogn)\),对于此题\(n=10\)的数据,足以。

优化

有什么更好的方法?

用\(n-1\)次中国剩余定理!

其实就是。

看样例:

我们先求解:

\[\begin{cases}x\equiv1\pmod{3}\\x\equiv1\pmod{5}\end{cases}
\]

我们知道,最后的得数还是同余方程,比如上边样例得出的:

\[x\equiv16\pmod{105}
\]

这类似一个合并过程,我们把两个方程合并成一个即可,如:

\[\begin{cases}x\equiv1\pmod{3}\\x\equiv1\pmod{5}\end{cases}
\]

可合并为:

\[x\equiv8\pmod{15}
\]

再与下一个方程合并即可,这样的合并仅是\(O(2logn)\)的,不过似乎正解是\(O(logn)\),差不多了......

\(Code\):

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int n;
struct node
{
ll a,b;
}e[15];
ll sum=1,now=1,ans=0,rt=1;
ll x,y;
inline void exgcd(ll a,ll b)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
ll t=x;
x=y;
y=t-a/b*y;
}
node merge(node m,node n)
{
node ans;
ans.a=m.a*n.a;
exgcd(n.a%m.a,m.a);
ll l=(x%m.a+m.a)%m.a;
l=l*m.b%ans.a*n.a%ans.a;
exgcd(m.a%n.a,n.a);
ll r=(x%n.a+n.a)%n.a;
r=r*n.b%ans.a*m.a%ans.a;
ans.b=(l+r)%ans.a;
return ans;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&e[i].a,&e[i].b);
node o=e[1];
for(int i=2;i<=n;i++) o=merge(o,e[i]);
printf("%lld\n",o.b);
return 0;
}

不过码量大一些,我想这么小的数据就不必了吧。


(这一部分在题解区没有,不想放上)

\(upd:2020.2.29(\text{真是特别的一天(其实我妈并不赞同我今晚颓电脑,不过还是完成二月的任务吧)})\)

我不会告诉你上述做法有锅的

所以给你一组数据:戳我

使用中国剩余定理是有前提的,就是模数必须互质。

都错了,傻眼了吧(不要怀疑数据)

老祖宗太不认真了,

你不能这样质疑,因为他们发现并补救了:

拓展中国剩余定理

题目链接:P4777 【模板】扩展中国剩余定理(EXCRT)

看某大佬博客懵逼许久,终于在挑战程序设计竞赛(第2版)

找到了答案(当然我是在纸质书上看的)

比如说样例:

我们以先前的合并思想,对前两个合并:

样例:

\[\begin{cases}x\equiv6\pmod{11}\\x\equiv9\pmod{25}\\x\equiv17\pmod{33}\end{cases}
\]

对前两个:

\[\begin{cases}x\equiv6\pmod{11}\\x\equiv9\pmod{25}\end{cases}
\]

易得:

\[x=11t+6(t\in Z)
\]

带进去就万事大吉了:

\[11t+6\equiv9\pmod{25}
\]

化简

\[11t\equiv3\pmod{25}
\]

不得不说你该会解吧,易得:

\[t_{min}=23
\]

答案的处理

其实你会反代的对不对?

\[x=11×23+6=259\equiv259\pmod{lcm(11 ,25)=275}
\]

这样就好了,一一合并即可。

复杂度是\(O(n\log n)\),可以通过本题。

\(Code\):

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=100005;
typedef long long ll;
inline long long mul(long long x,long long y,long long mod)
{
long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
return tmp<0 ? tmp+mod : tmp;
}
struct node
{
ll n,m;//m是模数,n是余数
}a[MAXN];
ll x,y,ans=1;
void exgcd(ll a,ll b)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
ll t=x;
x=y;
y=t-a/b*y;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll solve(ll a,ll b,ll c)
{
ll g=gcd(a,b);
if(c%g!=0) return -1;
a/=g,b/=g,c/=g;
exgcd(a,b);
x=x*c;
x=(x%b+b)%b;
return x;
}
node merge(node x,node y)
{
node ans;
ans.m=(x.m/gcd(x.m,y.m))*y.m;
ll t=solve(x.m,y.m,(y.n+y.m-x.n)%y.m);
if(t<0)
{
ans.n=-1;
return ans;
}
ans.n=mul(t,x.m,ans.m);
ans.n=(ans.n+x.n)%ans.m;
return ans;
}
ll n;
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].m,&a[i].n);
node rt=a[1];
for(int i=2;i<=n;i++)
{
rt=merge(rt,a[i]);
if(rt.n<0)
{
printf("-1\n");
return 0;
}
}
printf("%lld\n",rt.n);
return 0;
}

这个代码是会\(WA\)一个点被卡精度的的,不过大力快速乘(不懂大佬的方法)或是__int128并没什么意义,于是就......

学习笔记:中国剩余定理(CRT)的更多相关文章

  1. 【学习笔记-中国剩余定理】POJ1006 Biorhythms

    Biorhythms Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 139500   Accepted: 44772 Des ...

  2. 学习笔记 - 中国剩余定理&扩展中国剩余定理

    中国剩余定理&扩展中国剩余定理 NOIP考完回机房填坑 ◌ 中国剩余定理 处理一类相较扩展中国剩余定理更特殊的问题: 在这里要求 对于任意i,j(i≠j),gcd(mi,mj)=1 (就是互素 ...

  3. 中国剩余定理 CRT

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

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

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

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

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

  6. Hbase 学习笔记4----原理

    MapReduce 中如何处理HBase中的数据?如何读取HBase数据给Map?如何将结果存储到HBase中? Mapper类:包括一个内部类(Context)和四个方法(setup,map,cle ...

  7. 五毛的cocos2d-x学习笔记06-处理用户交互

    前几篇感觉自己在写教育文章,╮(╯▽╰)╭.今天换成开发者的口吻,毕竟我也是在边学边写博客. 处理用户交互包括:单点触摸.多点触摸.事件传递.传感器.物理按键等部分. 单点触摸: 触摸事件传递顺序 o ...

  8. Three.js学习笔记04--纹理

    1 纹理由图片组成  3D世界的纹理由图片组成. 将纹理以一定的规则映射到几何体上,一般是三角形上,那么这个几何体就有纹理皮肤了. 首先应该有一个纹理类,其次是有一个加载图片的方法,将这张图片和这个纹 ...

  9. Git学习笔记04-管理修改

    Git跟踪并管理的是修改,而非文件.新增文件,修改一行,删除一点,都算是修改. 在.git工作区新增一个文件,test.txt,输入test git ...然后git add ​ ​ add之后修改t ...

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

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

随机推荐

  1. map或者对象转换

    map或者对象转换为具有相同字段的对象 List<Example> errorCodeExcelBeanList = JSONObject.parseArray(((JSONObject) ...

  2. XCOJ 1249: 全自动奖学金计算系统

    1249: 全自动奖学金计算系统 时间限制: 1 Sec  内存限制: 64 MB提交: 305  解决: 54 标签提交统计讨论版 题目描述 宣城校区从今年开始,在原有奖学金制度上,设立专项奖学金. ...

  3. ES6简单语法

    ES6 简单语法: 变量声明 ES5 var 声明变量为全局变量 会变量提升 ES6 let 声明的变量为块级变量 且不能重复声明 不存在变量提升 # {}一个大括号为一个作用域 ES6 const ...

  4. C语言入门第十章----结构体

    C语言结构体从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,是由int.char .float等基本类型组成的,你可以认为结构体是一种聚合类型. 在实际开发中,我们可以将一组类型不同的. ...

  5. 添加COOKIE

    HttpCookie userinfoCookie = new HttpCookie("userinfo"); JObject o = new JObject();//JObjec ...

  6. php 基础知识 post 和get 两种传输方式的区别

    1.post更安全(不会作为url的一部分,不会被缓存.保存在服务器日志.以及浏览器浏览记录中) 2.post发送的数据量更大(get有url长度限制) 3.post能发送更多的数据类型(get只能发 ...

  7. select模块

    select模块 1.      select模块 源:select.py This module provides access to the select() and poll() functio ...

  8. hbase单机版安装

    hbase单机版安装 1.      hbase单机版安装 HBase的安装也有三种模式:单机模式.伪分布模式和完全分布式模式. hbase依赖于Hadoop和Zookeeper. 这里安装的是单机版 ...

  9. hexo 安装和部署

    因为投递论文需要个人网站,所以今天又来了一次hexo 安装和部署. 参考官方文档:https://hexo.io/zh-cn/docs/ git是需要的哈.自行安装 node需要大于8.10 node ...

  10. 【PAT甲级】1026 Table Tennis (30 分)(结构体排序,trick较多)

    题意: 输入一个正整数N(<=10000),表示客户(对)的大小,接着输入N行数据,每行包括一对顾客到场的时间,想要玩的时间,以及是否是VIP客户.接下来输入两个正整数K,M(K<=100 ...