POJ 2891 Strange Way to Express Integers (解一元线性方程组)

求解一元线性同余方程组:

x=ri(mod ai) i=1,2,...,k

解一元线性同余方程组的一般步骤:
先求出前两个的解,即:
x=r1(mod a1)     1
x=r2(mod a2)     2
1式等价于x=r1+a1*m,2式等价于x=r2+a2*n
联立可得:m*a1-n*a2=r2-r1=c
若方程有解,则必须(a1,a2)|c
设d=(a1,a2),那么如果有解,即可求得
  m*a1-n*a2=d的解,m=m'
则   m*a1-n*a2=c的解,m0=m'*c/d
通解m*=m0+(a2/d)*i
令s=a2/d,则可以求得m的最小解
  m=(m0%s+s)%s
带入x=r1+a1*m,即可求出解x,设为x0

接下来,由
x=r1(mod a1)     1
x=r2(mod a2)     2
得出x=x0=r1(mod a1),x=x0=r2(mod a2)
由定理可得,x=x0(mod [a1,a2])
设a=lcm(a1,a2),即可将1式和2式合并成一项。
接下来的就重复上面步骤即可。

#include <iostream>
#include <stdio.h>

using namespace std;
int k;
//求解方程ax+by=gcd(a,b)
long long exgcd(long long a,long long b,long long &x,long long &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    long long g=exgcd(b,a%b,x,y);
    long long tmp=x;
    x=y;
    y=tmp-(a/b)*y;
    return g;
}
int main()
{
    long long a1,a2,r1,r2,d,c;
    long long x,y,x0;
    long long s; //s=a2/d;
    while(scanf("%d",&k)!=EOF){
        bool flag=true;
        scanf("%I64d%I64d",&a1,&r1);
        for(int i=1;i<k;i++){
            scanf("%I64d%I64d",&a2,&r2);
            if(!flag)
                continue;
            /*
            解x=r1(mod a1)
              x=r2(mod a2)
            相当于
            解不定方程:x*a1+y*a2=r2-r1
            先求解方程:x*a1+y*a2=r2-r1=gcd(a1,a2)
            得出解x,则方程x*a1+y*a2=r2-r1的解x0=x*(r2-r1)/gcd(a1,a2)=x*c/d
            令s=a2/d,那么
            x0的最小解为:x0=(x0%s+s)%s
            即可得出解x=r1+x0*a1
            然后将x赋值给r1,lcm(a1,a2)赋值给a1,继续求解。
            */
            c=r2-r1;
            d=exgcd(a1,a2,x,y);
            if(c%d!=0){
                flag=false;
                continue;
            }
            x0=x*c/d;
            s=a2/d;
            x0=(x0%s+s)%s;
            r1=r1+x0*a1;
            a1=a1*a2/d;
        }
        if(flag)
            printf("%I64d
",r1);
        else
            printf("-1
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/chenxiwenruo/p/3553163.html