首页 > 其他分享 >中国剩余定理

中国剩余定理

时间:2023-01-29 18:33:22浏览次数:60  
标签:剩余 公倍数 定理 除以 int 中国 余数 LL

中国剩余定理

先看一道\(poj\)上的题目:【\(POJ1006\)】 \(Biorhythms\)

题意
  人自出生起就有体力,情感和智力三个生理周期,分别为\(23\),\(28\)和\(33\)天。一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。

分析
  首先我们要知道,任意两个峰值之间一定相距整数倍的周期。假设一年的第\(N\)天达到峰值,则 下次 达到峰值的时间为\(N+Tk\)
(\(T\)是周期,\(k\)是任意正整数)。所以,三个峰值同时出现的那一天(\(S\))应满足
\(S=N_1+T_1∗k_1=N_2+T_2∗k_2=N_3+T_3∗k_3\)
\(N_1,N_2,N_3\)分别为为体力,情感,智力出现峰值的日期, \(T_1,T_2,T_3\) 分别为体力,情感,智力周期。 我们需要求出\(k_1,k_2,k_3\)三个非负整数使上面的等式成立。

想直接求出\(k_1,k_2,k_3\)貌似很难,但是我们的目的是求出\(S\), 可以考虑从结果逆推。根据上面的等式,\(S\) 满足三个要求:

  • 除以\(T_1\)余数为\(N_1\)
  • 除以\(T_2\)余数为\(N_2\)
  • 除以\(T_3\)余数为\(N_3\)

这样我们就把问题转化为求一个 最小数,该数

  • 除以\(T_1\)余\(N_1\)
  • 除以\(T_2\)余\(N_2\)
  • 除以\(T_3\)余\(N_3\)

这就是著名的中国剩余定理,我们的老祖宗在几千年前已经对这个问题想出了一个精妙的解法。依据此解法的算法,时间复杂度可达到\(O(1)\)

中国剩余定理

在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以\(3\)余\(2\)),五五数之剩三(除以\(5\)余\(3\)),七七数之剩二(除以\(7\)余\(2\)),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。具体解法分三步:

  • 找出三个数:

    • 从\(3\)和\(5\)的公倍数中找出被\(7\)除余\(1\)的最小数\(15\)
    • 从\(3\)和\(7\)的公倍数中找出被\(5\)除余\(1\) 的最小数\(21\)
    • 从\(5\)和\(7\)的公倍数中找出除\(3\)余\(1\)的最小数\(70\)
  • 用\(15\)乘以\(2\)(\(2\)为最终结果除以\(7\)的余数),用\(21\)乘以\(3\)(\(3\)为最终结果除以\(5\)的余数),同理,用\(70\)乘以\(2\)(\(2\)为最终结果除以\(3\)的余数),然后把三个乘积相加\(15∗2+21∗3+70∗2\),得到和\(233\)。

  • 用\(233\)除以\(3,5,7\)三个数的最小公倍数\(105\),得到余数\(23\),即\(233\%105=23\)
    。这个余数\(23\)就是符合条件的最小数。

就这么简单。我们在感叹神奇的同时不禁想知道古人是如何想到这个方法的,有什么基本的数学依据吗?

  我们将“孙子问题”拆分成几个简单的小问题,从零开始,试图揣测古人是如何推导出这个解法的。

首先,我们假设:

  • \(n_1\)是满足除以\(3\)余\(2\)的一个数,比如\(2,5,8\)等等,也就是满足\(3∗k+2(k>=0)\) 的一个任意数。
  • \(n_2\)是满足除以\(5\)余\(3\)的一个数
  • \(n_3\)是满足除以\(7\)余\(2\)的一个数

有了前面的假设,我们先从\(n_1\)这个角度出发,已知\(n_1\)满足除以\(3\)余\(2\),能不能使得\(n_1+n_2\)的和仍然满足除以\(3\)余\(2\)?进而使得\(n_1+n_2+n_3\)的和仍然满足除以\(3\)余\(2\)?

 这就牵涉到一个 最基本数学定理,如果有\(a\%b=c\),则有\((a+k∗b)\%b=c\)(\(k\)为非零整数),换句话说,如果一个除法运算的余数为\(c\)
,那么被除数与\(k\)倍的除数相加(或相减)的和(差)再与除数相除,余数不变。

以此定理为依据,如果\(n_2\)是\(3\)的倍数,\(n_1+n_2\)就依然满足除以\(3\)余\(2\)。同理,如果\(n_3\)也是\(3\)的倍数,那么\(n_1+n_2+n_3\)
的和就满足除以\(3\)余\(2\)。这是从\(n_1\)的角度考虑的,再从\(n_2\),\(n_3\)的角度出发,我们可推导出以下三点:

  • 为使\(n_1+n_2+n_3\)的和满足除以\(3\)余\(2\),\(n_2\)和\(n_3\)必须是\(3\)的倍数

  • 为使\(n_1+n_2+n_3\)的和满足除以\(5\)余\(3\),\(n_1\)和\(n_3\)必须是\(5\)的倍数

  • 为使\(n_1+n_2+n_3\)的和满足除以\(7\)余\(2\),\(n_1\)和\(n_2\)必须是\(7\)的倍数

因此,为使\(n_1+n_2+n_3\)的和作为“孙子问题”的一个最终解,需满足:

  • \(n_1\)除以\(3\)余\(2\),且是\(5\)和\(7\)的公倍数。
  • \(n_2\)除以\(5\)余\(3\),且是\(3\)和\(7\)的公倍数。
  • \(n_3\)除以\(7\)余\(2\),且是\(3\)和\(5\)的公倍数。

所以,孙子问题解法的本质是:

  • 从\(5\)和\(7\)的公倍数中找一个除以\(3\)余\(2\)的数\(n_1\)
  • 从\(3\)和\(7\)的公倍数中找一个除以\(5\)余\(3\)的数\(n_2\)
  • 从\(3\)和\(5\)的公倍数中找一个除以\(7\)余\(2\)的数\(n_3\)

再将三个数相加得到解。在求\(n_1,n_2,n_3\)
时又用了一个小技巧,以\(n_1\)为例,并非从\(5\)和\(7\)的公倍数中直接找一个除以\(3\)余\(2\)的数,而是 先找一个 除以\(3\)余\(1\)的数,再乘以\(2\)。也就是先求出\(5\)和\(7\)的公倍数模\(3\)下的 逆元再用逆元去乘余数

这里又有一个数学公式,如果\(a\%b=c\),那么\((a∗k)\%b=a\%b+a\%b+…+a\%b=c+c+…+c=k∗c(k>0)\),也就是说,如果一个除法的余数为\(c\),那么被除数的\(k\)倍与除数相除的余数为\(k∗c\)。展开式中已证明。

最后,我们还要清楚一点,\(n_1+n_2+n_3\)
只是问题的一个解,并不是最小的解。如何得到最小解?我们只需要从中最大限度的减掉\(3,5,7\)的公倍数\(105\)即可。道理就是前面讲过的定理 如果\(a\%b=c\),则有\((a−k∗b)\%b=c\)
所以\((n_1+n_2+n_3)\%105\)就是最终的最小解。

这样一来就得到了中国剩余定理的公式:

【中国剩余定理公式】

设\(x \in Z\),有

\[\large \left\{\begin{matrix} x \equiv a_1(mod \ m_1) & \\ x \equiv a_2(mod \ m_2) & \\ x \equiv a_3(mod \ m_3) & \\ ... & \\ x \equiv a_n(mod \ m_n) & \end{matrix}\right. \]

令$$
\large \left{\begin{matrix}
M=m_1m_2m_3...m_n & \
M_i=M/m_i& \
t_i 是M_i关于m_i 的逆元,即M_i
t_i \equiv 1 (mod \ m_i)
\end{matrix}\right.

\[ 则 $$x=\sum_{i=1}^{n}a_iM_it_i\]

【代码实现】

模数互质

P3868 [TJOI2009] 猜数字

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 20;
int n;
LL a[N], m[N];
LL ans, x, y;

// P3868 [TJOI2009] 猜数字
/**
 由 bi | (n-ai), 也就是 n % b[i] =a[i]
 标准的中国剩余定理
 */

//快速乘
LL ksc(LL a, LL b, LL mod) {
    LL res = 0;
    while (b) {
        if (b & 1) res = (res + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return res;
}

//扩展欧几里得
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main() {
    cin >> n;

    // a[i]:余数,b[i]:分组个数
    for (int i = 1; i <= n; i++) cin >> a[i];

    LL M = 1;
    for (int i = 1; i <= n; i++) cin >> m[i], M *= m[i]; // M是累乘积

    // a[i]可能为负数,预处理成正数
    for (int i = 1; i <= n; i++) a[i] = (a[i] % m[i] + m[i]) % m[i];

    // 中国剩余定理
    for (int i = 1; i <= n; i++) {
        exgcd(M / m[i], m[i], x, y);                  // 求逆元
        x = (x % m[i] + m[i]) % m[i];                 // 防负数
        ans = (ans + ksc(a[i], M / m[i] * x, M)) % M; // 快速乘
    }

    printf("%lld\n", ans);
    return 0;
}

P1495 【模板】中国剩余定理(CRT)/曹冲养猪

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10;
int a[N], m[N];
int n;

void exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b)
        x = 1, y = 0;
    else {
        exgcd(b, a % b, y, x);
        y -= a / b * x;
    }
}

int main() {
    cin >> n;
    LL M = 1;

    // a[i]:余数,m[i]:分组个数
    // 注意录入顺序,与P3868进行对比
    for (int i = 1; i <= n; i++) {
        cin >> m[i] >> a[i];
        M *= m[i];
    }

    LL res = 0, x, y;
    for (int i = 1; i <= n; i++) {
        exgcd(M / m[i], m[i], x, y);
        res += a[i] * M / m[i] * x;
    }

    printf("%lld\n", (res % M + M) % M);
    return 0;
}

中国剩余定理扩展——求解模数不互质情况下的线性方程组:

大神博客

推荐题目

模数不互质模板:洛谷P4777 【模板】扩展中国剩余定理(EXCRT).

标签:剩余,公倍数,定理,除以,int,中国,余数,LL
From: https://www.cnblogs.com/littlehb/p/17073570.html

相关文章

  • [AHOI2009] 中国象棋 题解
    每行每列的炮数量\(\leq2\),那么整个图就可以被分解为一些环和链。考虑答案的二元生成函数,显然环和链分别的生成函数都是平凡的多项式,而答案的多项式无非是加起来后求exp......
  • Lucas 定理
    简述当问题规模很大,而模数是一个不大的质数的时候,就不能简单地通过递推求解来得到答案,需要用到Lucas定理。LucasLucas定理内容如下:对于质数\(p\),有\[\binom{n}{m}......
  • 机器人液化越狱!中国团队实现终结者幻想,灵感竟来自海参
    机器人液化越狱!中国团队实现终结者幻想,灵感竟来自海参投递人 itwriter 发布于 2023-01-2722:50 评论(0) 有1091人阅读 原文链接 [收藏] « »晨羿阁发自......
  • 开源的Siri不一样的中国风
    相信大家应该都知道Siri,尤其是使用iPhone手机的朋友们。但是在日常生活中,能灵活运用Siri的却寥寥无几。很多人不爱用 你知道Siri可以帮我们做哪些事情么?拨打电话、发送短信......
  • 中国联通家庭智能网关 EPON/4+1+WiFi(2.4G) 管理员登录
     光猫型号硬件版本软件版本天邑TEWA-800EV3.0Tianyi_V3.1.3一、打开中国联通智能网关登录界面GoogleChrome打开http://192.168.1.1/二、获取sessionKey......
  • GitHub2021年度报告:中国开发者数量全球第2,最受欢迎的语言?
    临近年底,各大平台年终报告频频发布。作为程序员,应该关注些什么呢?近日,全球最大开发者社区GitHub重磅发布了《2021年度Octoverse报告》,本报告首次结合了来自GitHub上,超过40......
  • 矩阵树定理
    简述Kirchhoff矩阵树定理(简称矩阵树定理)解决了一张图的生成树个数计数问题。主要步骤无向图假设现在给定一个无向图\(G\)定义度数矩阵\(D\):若存在边\((u,v,w)\),则\(D......
  • 2022年中国服务机器人行业研究|报告PDF分享(附原数据表)
    报告链接:http://tecdat.cn/?p=31419随着大量企业的涌入,服务机器人产业化即将到来。经过多年的发展,我国已经实现了完整的服务机器人产业生态系统。在常态化疫情防控、人口......
  • 【学习笔记】Burnside引理与Polya定理(无证)
    群论笔记Burnside引理\[置换后本质不同的数量=\frac{1}{置换方式总数}\times所有置换后与原来相同的构造方案\]注意:单位元也是置换Polya定理举例说明。考虑立方体......
  • 如何在 Ubuntu 中卸载 deb 包 | Linux 中国
    如何在Ubuntu中卸载deb包|Linux中国原创 邀你一起加入 Linux中国 2022-08-0120:08 发表于海南收录于合集#译者:geekpi364个 导读:删除.deb文件的最简单和......