中國剩余定理(模數不互質)


上一篇博客寫的是中國剩余定理模數不互質的情況,然鵝——還存在着模數互質的情況,而原來的做法就沒有辦法用了

那我們現在該怎么做呢?


 

原來的思路是對於每一個方程,我們找出一個基礎數,使得基礎數滿足該方程要求。因為是互質的關系,所以所有基礎數加起來也不會沖突。(這個由最小公倍數保證)

還是這個栗子 存在一個數x,除以3余2,除以5余3,除以7余2,然后求這個數

3的基礎數是35,滿足除以3余2,而且是5和7的倍數,5,7同理。也就是說:基礎數幾倍幾倍的變化是不會造成突然冒出來一個什么數%5或%7出現了余數


而現在模數不互質,還是舉個栗子存在一個數x,除以6余4,除以8余2,除以9余7,然后求這個數

答案手推出來是34,如果仍然按照原來的做法lcm為72,6的基礎數為。。。誒誒?怎么推不出來?72/6=12,ok,12不滿足,再擴大,emm,還是不滿足,再擴大。。。

好吧,相信大家已經發現了!12是6的倍數啊!再怎么擴大也不可能滿足條件啊!

這就是互質與不互質的區別:不互質可能會導致基礎數是模數的倍數,那么這個算法就涼涼了

那就讓我們換一個思維方式吧!

可以先對第一個方程求解出一個滿足條件的x,再去看下一個方程,在這個x的基礎上,加上一個滿足下一個方程的x',同時不破壞前面方程的要求。

也就是說,我們去判斷一個方程有沒有解,解是多少。這,這不就是擴歐嗎?

具體看代碼吧~

#include<bits/stdc++.h>
using namespace std;
int a[10],m[10],tong[103];
int exgcd(int a,int &x,int b,int &y)
{
    if(b==0){x=1;y=0;return a;}
    int x2,y2;
    int gcd=exgcd(b,x2,a%b,y2);
    x=y2;
    y=x2-a/b*y2;
    return gcd;
}
int main()
{
    freopen("crt.in","r",stdin);
    freopen("crt.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        scanf("%d%d",&a[1],&m[1]);
        //用lcm求當前到達過的方程中,所有模數的lcm,sum是最后的結果,但是每一次都會用
        //解出的x去更新它,fail判斷是否有解 
        int lcm=m[1],sum=a[1],fail=0;
        for(int i=2;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&a[i],&m[i]);
            a[i]=((a[i]-sum)%m[i]+m[i])%m[i];//sum就是要求的x,不斷更新 
            int d=exgcd(lcm,x,m[i],y);//lcm*x+m[i]*y+sum=a[i]才能保證x%m[i]=a[i] 
            if(a[i]%d==0) x=x*(a[i]/d)%m[i];
            else fail=1;
            sum+=x*lcm;//注意是乘lcm哦!不然可能會出現前面的方程沖突 
            lcm=lcm/d*m[i];//到現在這一個方程了,所有模數的最小公倍數 
            sum=(sum%lcm+lcm)%lcm;
        }
        if(fail) printf("No\n");
        else printf("%d\n",sum); 
    }
}
/*
3
4 6
2 8
7 9

3
2
3 5
4 7
3
4 6
2 8
7 9
2
1 2
2 4
*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM