中国剩余定理(孙子定理)+ exgcd求逆元

中国剩余定理

  中国剩余定理又叫孙子定理。在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之 剩二(除以7余2),问物几何?”这个问题称为“孙子问题”,解决的孙子问题的一般解法就叫孙子定理又叫 天朝 中国剩余定理。
具体解法分两步
  1.找出3和5公倍数中除7余2的最小的数(30)、3和7公倍数中除5余3的最小的数(63)、5和7公倍数中除3余2的最小的数(140),然后将这三个数相加得233。(ps:为了简化运算第一个数可以找 % 7 = 1的数之后在乘2,其他两个数同理分别乘3、2。)
  而寻找取模后为1的数即为寻找其逆元,逆元的概念后面会说
  2.用233除以3、5、7的最小公倍数105,得到余数23(即233%105 = 23),23即为所求。

是不是一脸懵(如果明明白白的请无视我这个菜鸡),我第一次看也是想说就这么简单???

但这是有数学依据的

  设这三个数分别为n1、n2、n3。因为n1 % 7 == 2,n2、n3又都是7的倍数所以,(n1 + n2 + n3) % 7 == 2,其他两个同理,所以最后得到的数233(n1+n2+n3)就满足孙子问题中的三个条件,但这不一定是最小的解

那么如何得到最小解?
  只需要在该解的基础上最大限度的减去3、5、7的公倍数即可(即对该解取模233%105),为什么?因为这样无论怎么减都不会影响其对于3、5、7的模数。

逆元

  给出 a 和 m ,一个数有逆元的充分必要条件是gcd(a,m)=1,此时逆元唯一存在,这时方程 ax ≡ 1(mod m)的最小整数解 x 称为 a 模 m 的逆元
  逆元的含义:
    在模m意义下,一个数a如果有逆元x,那么除以a相当于乘x。

  为什么要有乘法逆元呢?

    当我们要求(a/b) mod p的值,且a很大,大到会溢出;或者说b很大,达到会爆精度。无法直接求得a/b的值时,我们就要用到乘法逆元。

  那么如何求解逆元呢?
    根据上文我们知道ax ≡ 1(mod m)有解的条件是a和m互素,即gcd(a,m) == 1.

    易知ax mod m = ax - (ax / m) * m
    所以ax ≡ 1(mod m) 等价于 ax - (ax / m) * m = 1
    提出m得
      ax + m( - ax / m) = 1
    令y = -(ax/m)得
      ax + my = 1
    所以求解 ax ≡ 1(mod m)等价于求解 ax + my = 1 ,那么就可以用扩展欧几里得定理求解。

扩展欧几里得定理(exgcd):

  给出整数a,b,n,求方程 ax + by = n 的所有整数解。有解的充分必要条件是gcd(a,b)可以整除 n 。简单解释如下:
    令 a = gce(a,b) * a’、 b = gcd(a,b) * b’ , 则有 ax + by = gcd(a,b)(a’x + b’y) = n;如果 x 、y 、a’ 、b’都是整数,那么n必须是gcd(a,b)的倍数才有整数解。
  exgcd解出的 x 为 ax + by = gcd(a,b) 中的 x ,若要求 ax + by = n中的 x,两边还要乘上 n / gcd(a,b)。
  由欧几里得算法,得

    ax+by=gcd(a,b)=gcd(b,a mod b)=bx′+(a mod b)y′

  代入上文的a mod b = a - ⌊ a / b ⌋ b 得
     ax + by = bx’ + (a - ⌊ a / b ⌋ b) y’
        = bx’ + ay’ - ⌊ a / b ⌋ by’
        = ay’ + b(x’ - ⌊ a / b ⌋y’)
    得 x = y′ , y = x′ − ⌊ a / b ⌋y′
  边界情况分析,ax′+by′=gcd(a,b),当 b=0 时,a 为 gcd(a,b),当且仅当 x′=1时等式成立,y′ 可以为任意值,为方便起见,设y′=0,那么得到以下代码:

void exgcd(int a,int b,int &x,int &y)
{
	if(b==0){x=1;y=0;return;}
	exgcd(b,a%b,x,y);
    int z = x; x = y; y = z - (a/b)*y;
}

求出的 x 即为 a 模 b 的逆元。

介绍完了看看这道例题:

luogu 曹冲养猪

题目描述
自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。举个例子,假如有 1616 头母猪,如果建了 33 个猪圈,剩下 11 头猪就没有地方安家了。如果建造了 55 个猪圈,但是仍然有 11 头猪没有地方去,然后如果建造了 77 个猪圈,还有 22 头没有地方去。你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?

输入格式
第一行包含一个整数 n (建立猪圈的次数),接下来 n 行,每行两个整数 ai,bi, 表示建立了 ai个猪圈,有 bi 头猪没有去处。你可以假定 ai,aj互质。

输出格式
输出包含一个正整数,即为曹冲至少养母猪的数目。

输入

3
3 1
5 1
7 2

输出

16
#include<cstdio>
#include<iostream>
#include<cmath>

#define ll long long

using namespace std;

ll n,a[15],b[15],c[15],mul = 1,ans;

void exgcd(ll a,ll b,ll &x, ll&y) {
    if(b == 0) {x = 1;y = 0;return;}
    exgcd(b,a%b,x,y);
    int z = x; x = y; y = z-y*(a/b);
}

int main( ) {
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) {
        scanf("%d%d",&a[i],&b[i]);
        mul *= a[i];//求出所有数的最小公倍数(因为每个数都互质)
    }
    for(int i = 1; i <= n; i++) {
        c[i] = mul / a[i]; //除去a[i]所有数的最小公倍数
        ll x = 0, y = 0;
        exgcd(c[i],a[i],x,y);//求逆元
        ans += b[i] * c[i] * (x < 0 ? x + a[i]: x);//累加成其中一个解
    }
    printf("%lld",ans%mul);//输出最小解
    return 0;
}

两年没写博客了,如有错误欢迎斧正。

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值