poj 2891 Strange Way to Express Integers (求解线性同余方程组/模板)

题意:给你n个对数,ai,ki

X = a1 *x1 + k1

X = a2 *x2 + k2

.....

X = ai*xi  + ki

问你是否存在这样一个X,存在就输出该值,否则输出-1

思路:

对于模线性方程组,可以进行方程组合并,求出合并后的方程的解,这样就可以很快的推出方程的最终解,不管这样的方程有多少个,都可以俩俩解决,求得方程组的最终解。

x=b1(mod m1) (1);

x=b2(mod m2) (2);

 

m=lcm(m1,m2). 

 

首先,此次方程组有解的充分必要条件是gcd(m1,m2)|gcd(b1,b2),此时方程仅有一个小于m 的非负整数解,利用扩展欧几里德算法解出来。 

式(1)等价于x=b1+m1*y1;

式(2)等价于x=b2+m2*y2;

联立可得b1+m2*y1=b2+m2*y2,即m2*y2-m1*y1=b1-b2;  

根据之前所学模线性方程的方法,很容易得到此方程的解有y2,因此小于m的非负整数解即为(b2+m2*y2)%m。

明显这是其中一组解,y2+K*lcm(m1,m2)都是解(每次加上最小公倍数)。(k=0,1,2,3。。。)

代码:

#include <iostream>
#include <cstdio>
#define ll long long 

using namespace std;

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

ll solve(ll a[],ll r[],ll n)
{
    ll d,c,i,x,y,t;
    for(i=1;i<n;i++)
    {
        c=r[i]-r[i-1];
        d=exgcd(a[i-1],a[i],x,y);
        if(c%d!=0) return -1;
        t=a[i]/d;
        x=(x*(c/d)%t+t)%t;
        r[i]=a[i-1]*x+r[i-1];
        a[i]=a[i-1]*(a[i]/d);
    }
    return r[n-1];
}

int main() {
    ll n;
    ll a[100005];
    ll r[100005];
    while(cin>>n)
    {
        for(int i=0;i<n;i++)
        scanf("%lld %lld",&a[i],&r[i]);
        ll ans=solve(a,r,n);
        cout<<ans<<endl;
    }
    return 0;
}

 

原文地址:https://www.cnblogs.com/simplekinght/p/6817834.html