中国剩余定理模板 线性同余方程组 除数互质/ 除数不互质

1、首先,明确中国剩余定理解决的问题:求解同余方程组未知量N。

2、条件:已知方程组中方程个数k、被除数Mi数组、余数ai数组,且M数组中元素两两互质。

3、解决思路:

由孙子算经中的类似问题,我们得知:N=∑Ni*ai(i:1~k),所以问题的关键便在于求k个Ni。

求解Ni:

设MM=M[1]*M[2]*... ...M[k];

由孙子算经类推得:

①:Ni=1+M[i]*J(设J为任意常数)                  ②:Ni=MM/M[i]*L(L为任意常数)

所以有:

1+M[i]*J==MM/M[i]*L    ===>   -J*M[i]+MM/M[i]*L=1;

又因为G(M[i],MM/M[i])==1,所以有同余方程:-J*M[i]+MM/M[i]*L==G(M[i],MM/M[i]),然后扩展欧几里得解该方程,即得J,与L,进而可以求得Ni,最终求得N。

 

所以实现代码;

int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int gcd=exgcd(b,a%b,x,y);
    if(a*b>=0)
    {
        int temp=x;
        x=y;
        y=temp-a/b*y;
    }
    else
    {
        int temp=x;
        x=-y;
        y=a/b*y-temp;
    }
    return gcd;
}
int China(int M[],int a[],int k)
{
    int mm=1,ans=0;
    int L,J;
    for(int i=1;i<=k;++i)mm*=M[i];
    for(int i=1;i<=k;++i)
    {
        exgcd(mm/M[i],-M[i],L,J);
        int NTemp=1+J*M[i];
        ans+=NTemp*a[i];
    }
    return (ans%mm+mm)%mm;
}

被除数不互质的情况下

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
#define ll long long
using namespace std;
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    ll q=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return q;
}
int main(){
    ll a1,c1,a2,c2,x,y,t;
    ll n;
    while(scanf("%lld",&n)!=EOF)//n个式子
    {
        bool ff=1;
        scanf("%lld%lld",&a1,&c1);//第一个方程的被除数和余数
        for(ll i=1;i<n;i++)
        {
            scanf("%lld%lld",&a2,&c2);
            ll q=exgcd(a1,a2,x,y);
            if((c2-c1)%q)
            {
                ff=0;
            }
            t=a2/q;
            x=((x*(c2-c1)/q)%t+t)%t;

            c1+=a1*x;
            a1*=(a2/q);
        }
        if(ff==0)
        {
            printf("-1\n");//无解的情况
            continue;
        }
        printf("%lld\n",c1);
    }
    return 0;
}

The end;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值