中国剩余定理+扩展

最近有点不妙啊。- -。

前提知识:扩展欧几里得,乘法逆元,快速幂等。

中国剩余定理。CRT。

现在看来比较简单了。
他用来处理一堆形如
x≡ai(mod mi)的同余方程。
最后求x。
要用这个定理的前提是mi两两互质。
(注意我设的未知量的大小写)
定理内容:首先令M=m1 m2 。。。。。(所有m乘起来)。
然后,令Mi=M/mi,Ri为 Mi在模mi意义下的逆元。
那么ans=sigma ai *Mi *Ri mod(M)

为啥呢?
让我通俗易懂(高大上)地证明一波。

对于一个数aj来说,它对答案贡献的就是aj *Mj *Rj(看上面)。
那么这个数在mod (mj)意义下它就是aj 因为Rj是Mj在mj意义下的逆元乘起来为1,而对于非aj的数来说,比如ak,它对答案贡献就是ak * Mk * Rk,Mk里面含有mj,所以它在mod (mj)意义下就是0,其他所有非aj的数都如此,那么可以保证求出的答案在mod(mj)意义下就是aj,同理,对于所有的同余方程都如此。

下面上一份代码:

#include<cstdio>
#define N 100005
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return d;
}

int inverse(int a,int m){
    int x,y;
    int d=exgcd(a,m,x,y);
    if(d!=1)return -1;
    else return (x%m+m)%m;
}//求逆元 
int a[N],m[N],num;
int crt(){
    int M=1,ans=0; 
    for(int i=1;i<=num;i++)
    M*=m[i];
    for(int i=1;i<=num;i++){
        int Mi=M/m[i],Ri=inverse(Mi,m[i]);
        ans=(ans+1LL*a[i]*Mi*Ri%M)%M;
    }
    return ans;
}

int main(){
    scanf("%d",&num);
    for(int i=1;i<=num;i++)
    scanf("%d%d",&a[i],&m[i]);
    printf("%d\n",crt());
    return 0;
}

对于扩展版本就是mi两两不互质的情况。
我们考虑合并两个方程。就是对于两个方程。
x≡ai(mod mi)
x≡aj(mod mj)
改写为aj+mj*t1=ai+mi*t2
求解这个方程带入原式得到x,把新的m变为mi和mj的最小公倍数,因为mi和mj都可以整除它们最小公倍数,而x可以在这个基础上+-公倍数都不会对原来两个方程的答案造成影响,

代码懒得给了~~~。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值