poj2891

中国剩余定理考虑模数不互质的情况

太懒了> - <

详细解析

 

解同于方程组:

 
xr1(moda1)xr2(moda2)......xrn(modan)x≡r1(moda1)x≡r2(moda2)......x≡rn(modan)

其中模数不一定互质。

 

题解

若模数两两互质,我们可以用中国剩余定理来解。 
这里我们先考虑两个方程:

 
xr1(moda1)xr2(moda2)x≡r1(moda1)x≡r2(moda2)

我们可以写成:

 
x+y1a1=r1xy2a2=r2x+y1a1=r1x−y2a2=r2


相减得:y1a1+y2a2=r1r2y1a1+y2a2=r1−r2也就是ax+by=max+by=m的形式。 
这是可以用扩展欧几里德解的。 
gcd(a,b)/|mgcd(a,b)⧸|m那么方程就无解,直接输出-1。 
否则我们可以解出上式的y1y1。回带得到一个特解x0=r1y1a1x0=r1−y1a1。 
通解可以写成x=x0+klcm(a1,a2)x=x0+k∗lcm(a1,a2)也就是xx0(modlcm(a1,a2))x≡x0(modlcm(a1,a2))。 
这样我们就将两个方程合并为了一个。重复进行以上操作,我们最终能将n个方程全部合并,再用扩展欧几德得解出来就好了。

 

ll solve(){
    ll M=a[1],R=r[1],x,y,d;
    for(int i=2;i<=n;i++){
        d=exgcd(M,a[i],x,y);
        if((R-r[i])%d!=0) return -1;  //无解
        x=(R-r[i])/d*x%a[i]; //这才是真正的x,记得模a[i]。
        R-=x*M;   //特解x0,新的余数。
        M=M/d*a[i]; //新的模数。
        R%=M;
    }
    return (R%M+M)%M;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

下面是完整代码:

#include<cstdio>
#include<cctype>
#define ll long long
using namespace std;
ll a[100005],r[100005];
int k;

inline void read(ll &x){
    char ch=getchar();x=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
}

ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){x=1;y=0;return a;}
    else{ll tmp=exgcd(b,a%b,y,x);y-=(a/b)*x;return tmp;}
}

ll solve(){
    ll M=a[1],R=r[1],x,y,d;
    for(int i=2;i<=k;i++){
        d=exgcd(M,a[i],x,y);
        if((R-r[i])%d!=0)return -1;
        x=(R-r[i])/d*x%a[i];
        R-=x*M;
        M=M/d*a[i];
        R%=M;
    }
    return (R%M+M)%M;
}

int main(){
    while(~scanf("%d",&k)){
        for(int i=1;i<=k;i++){read(a[i]);read(r[i]);}
        printf("%lld\n",solve());
    }
}

 

posted @ 2018-05-15 11:42  lnyzo  阅读(67)  评论(0编辑  收藏  举报