中国剩余定理

中国剩余定理

类似于这样的问题:有一个数,模5余2,模7余3,模13余8,……,求这个数是多少?
实质上就是求一个模线性方程组。
{x≡a1(modr1)x≡a2(modr2)x≡a3(modr3)…x≡ak(modrk)\begin{cases} x \equiv a_1 \pmod {r_1} \\ x\equiv a_2 \pmod {r_2} \\ x\equiv a_3 \pmod{r_3} \\ \dots \\ x \equiv a_k \pmod{r_k} \end{cases}xa1(modr1)xa2(modr2)xa3(modr3)xak(modrk)
其中,r1,r2,…,rkr_1,r_2,\dots,r_kr1,r2,,rk互质。
中国剩余定理就是解决这种模数互质的模线性方程组的。
因为r1,r2,…,rkr_1,r_2,\dots,r_kr1,r2,,rk互质,所以,对于rir_iri,设Ai=∏j≠irjA_i=\prod_{ j\neq i}r_jAi=j=irj,则Ai,riA_i,r_iAi,ri是互质的,则必存在一个整数cic_ici,使得ci∗Ai%ri=1c_i*A_i \%r_i=1ciAi%ri=1,则设xi=ai∗ci∗Aix_i=a_i*c_i*A_ixi=aiciAi,则xi%ri=aix_i\%r_i=a_ixi%ri=ai。因为AiA_iAi是除了rir_iri以外的其他rrr值的最小公倍数,所以,xix_ixi 模其他的r,余数都为0,只有模rir_iri时,余数为aia_iai
这就是说,把xix_ixi加到满足其他方程(比如第j个方程,j≠ij\neq ij=i)的解xjx_jxj上,则(xi+xj)(x_i+x_j)(xi+xj) 也满足方程iii。同理,如果xjx_jxj 也是这么求出来的,则(xi+xj)(x_i+x_j)(xi+xj)也满足方程iii
那么,我们对于每一个方程,都按照这个方法求出来该方程的解。把这些解累加起来,你会发现,这个和仍然满足每一个方程。
x=∑i=1kai∗ci∗Aix=\sum\limits _{i=1}^k a_i*c_i*A_ix=i=1kaiciAi

对于x,如果我们加上所有的r值的最小公倍数,它仍然满足所有方程。
所以,只有存在x,则意味着有无穷多组解。
通解为:
x=∑i=1kai∗ci∗Ai+p∗∏i=1krix=\sum\limits _{i=1}^k a_i*c_i*A_i+p*\prod_{i=1}^kr_ix=i=1kaiciAi+pi=1kri
其中,p是任意整数。

扩展中国剩余定理

中国剩余定理采用的是构造法做的,要求模数互质。但是如果模数不互质,怎么办呢?
那么这就是扩展中国剩余定理要解决的问题了。
{x≡a1(modr1)x≡a2(modr2)x≡a3(modr3)…x≡ak(modrk)\begin{cases} x \equiv a_1 \pmod {r_1} \\ x\equiv a_2 \pmod {r_2} \\ x\equiv a_3 \pmod{r_3} \\ \dots \\ x \equiv a_k \pmod{r_k} \end{cases}xa1(modr1)xa2(modr2)xa3(modr3)xak(modrk)
首先取方程组的前两个方程:
x=k∗r1+a1=p∗r2+a2x=k*r_1+a_1=p*r_2+a_2x=kr1+a1=pr2+a2
k∗r1−p∗r2=(a2−a1)k*r_1-p*r_2=(a_2-a_1)kr1pr2=(a2a1)
这个形如ax+by=cax+by=cax+by=c的不定方程,用扩展欧几里得算法即可。
gcd(r1,r2)gcd(r_1,r_2)gcd(r1,r2)不能整除a2−a1a_2-a_1a2a1时,方程组无解。
否则,根据exgcd,求出k0k_0k0,满足k0∗r1−p∗r2=(a2−a1)k_0*r_1-p*r_2=(a_2-a_1)k0r1pr2=(a2a1)。k的通解为:k=k0+b∗(r2/gcd(r1,r2))k=k_0+b*(r_2/gcd(r_1,r_2))k=k0+b(r2/gcd(r1,r2))
代入到方程组x=k∗r1+a1x=k*r_1+a_1x=kr1+a1中,则有x=(k0+b∗(r2/gcd(r1,r2)))∗r1+a1=k0∗r1+b∗lcm(r1,r2)+a1x=(k_0+b*(r_2/gcd(r_1,r_2)))*r_1+a_1=k_0*r_1+b*lcm(r_1,r_2)+a_1x=(k0+b(r2/gcd(r1,r2)))r1+a1=k0r1+blcm(r1,r2)+a1
其中b为任意整数。
即:x≡(k0∗r1)+a1(modlcm(r1,r2))x \equiv(k_0*r_1)+a_1 \pmod{lcm(r_1,r_2)}x(k0r1)+a1(modlcm(r1,r2))
这个方程相当于合并了原来的两个方程,而形式上又和原来的方程一致。
继续采用这个方法,不断地合并方程组中的两个方程,直到最后合并为一个方程,则得到了x的通解了。

注意在这个过程中,要注意求出的k0k_0k0k∗r1−p∗r2=(a2−a1)k*r_1-p*r_2=(a_2-a_1)kr1pr2=(a2a1)的解,而不是k∗r1−p∗r2=gcd(r1,r2)k*r_1-p*r_2=gcd(r_1,r_2)kr1pr2=gcd(r1,r2)的解。前者是后者的倍数。

一道例题:poj2891 (扩展中国剩余定理模板题)

给出一个模线性方程组,模数不互质,求方程的最小正整数解。如果无解,输出-1.

// ax+by=c
// x%a1=r1
// x%a2=r2
// x=k*a1+r1=p*a2+r2
// k*a1+q*a2=r2-r1
// a1,a2,r2-r1已知,所以可以通过exgcd求出k和q。
// 求出一个k值,设为k0.
// k=k0+a2/gcd(a1,a2)
// x=k*a1+r1=(k0+b*a2/(gcd(a1,a2)))*a1+r1=k0*a1+b*lcm(a1,a2)+r1
// x的通解 x=lcm(a1,a2)*b+k0*a1+r1
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long int
#define abs(a) (a>0?a:-(a))
LL m,ans;
#define MAXN 1005
LL arr[MAXN],r[MAXN];
LL a,b,d,x,y,lcm;
void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(!b)
    {
        d=a,x=1,y=0;
    }
    else
    {
        exgcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}
bool noans;
int main()
{
    while(scanf("%d",&m)!=-1)
    { 
    noans=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&arr[i],&r[i]);
    }
    for(int i=1;i<m;i++)
    {
        exgcd(arr[i],arr[i+1],d,x,y);
        if(abs(r[i+1]-r[i])%d)
        {
            noans=1;
            break;
        }
        x=(x*((r[i+1]-r[i])/d)%(arr[i+1]/d)+arr[i+1]/d)%(arr[i+1]/d);
        lcm=arr[i]*arr[i+1]/d;
        arr[i+1]=lcm,r[i+1]=(x*arr[i]+r[i])%lcm;
    }
    if(noans==0)
    ans=r[m];
    else
    ans=-1;
    printf("%lld\n",ans);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值