一次同余方程求解模板(中国剩余定理)

此博客转载于网络(http://www.cnblogs.com/lmlyzxiao/p/4931129.html)

一次同余方程的求解步骤

1:求gcd(a,m)

2:令d = gcd(a,m) 如果d不能整除b则无解,否则转3

3:根据ex_gcd 求得一个解x0;

用扩展欧几里得求解的具体做法如下:

(1):用ex_gcd求得满足 ax' + my' = d 的x'和y'。具体方法是将 ax'+my' = d 变形可以得到 ax' = d - my';

对变形后的式子两边同时取模m得 ax'Ξd(mod)m,至此可见x'是同余方程的解

(2):根据x'求x0。具体方法是:由于d能整除b 设 p = b/d,则根据同余式的性质得到:a(px')≡dp(mod)m即:a(px')≡b(mod)m.因此x0 = px' = b/d*x'(mod)m.

4:根据求得的x0可以得到其他d-1个解为 xi = (x0 + i*m/d)(mod)m, i = 1,2,...d-1.

然后根据上面的方法去解上面的题。代码是求得方程组小于m的非负整数解。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
#include <queue>
#include <map>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 1000005;

typedef long long LL;

LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
   if(b == 0){
        x = 1;
        y = 0;
        return a;
   }
   LL r = ex_gcd(b,a%b,x,y);
   LL t = x;
      x = y;
      y = t - a/b*y;
      return r;
}
int main()
{
    LL i,n,a1,r1,a2,r2,ans,a,b,c,d,x0,y0;
    while(scanf("%lld",&n)!=EOF){
        bool flag = 1;
        scanf("%lld%lld",&a1,&r1);
        for( i=1;i<n;i++){
            scanf("%lld%lld",&a2,&r2);
            a = a1;
            b = a2;
            c = r2-r1;
            LL d = ex_gcd(a,b,x0,y0);
            if(c%d!=0){
                flag = 0;
            }
            int t = b/d;
            x0 = (x0*(c/d)%t+t)%t;//保证x0为正
            r1 = a1*x0 + r1;
            a1 = a1*(a2/d);


        }
        if(!flag){
            puts("-1");
            continue;
        }
        printf("%lld
",r1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zznulw/p/6704819.html