POJ 2891 Strange Way to Express Integers(一元线性同余方程组模版题)

题意:给出n个模方程组:x mod ai = ri。求x的最小正值。如果不存在这样的x,那么输出-1.



涉及的数论知识:

对于一般式ax ≡ b(mod m)

当a=1时,两个同余方程就可以合并成一个同余方程


比如对于本题:

x mod a1=r1

x mod a2=r2

有不定方程:

x=r2+a2*y2

x=r2+a2*y2

联立:

a1y1+a2*(-y2)=r2-r1

可以通过扩展gcd求解出y1,回带解得特解(x*)

所以通解是满足合并后的同余方程的所有同余类解:x mod (lcm(a1,a2)) =(x*) (由数论结论知只有一类同余解,证明不说辣)


经过n-1次合并解出在0~lcm(a1,a2,a3...an)内的特解(x*) 就解决辣




//Accepted	148K	16MS	C++	989B
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
ll a1,r1,a2,r2;
ll x,y;
int n;
ll e_gcd(ll a,ll b,ll&x,ll&y)
{
    ll ans;
    if(b==0)
    {
        ans=a;
        x=1,y=0;
    }
    else
    {
        ans=e_gcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    return ans;
}
bool flag;
int main()
{
    while(~scanf("%d",&n))
    {
        flag=0;
        scanf("%I64d%I64d",&a1,&r1);
        for(int i=1;i<n;i++)
        {
            scanf("%I64d%I64d",&a2,&r2);
            ll R=r2-r1;
            ll d=e_gcd(a1,a2,x,y);
            ll tmp=a2/d;
            if(R%d) flag=1;
            r1=((x*R/d)%tmp+tmp)%tmp*a1+r1;//合并成新的同余方程
            a1=a1*(a2/d);//合并成新的同余方程
        }
        if(flag) puts("-1");
        else
        {
            ll lcm = a1;
            ll ans=(r1%lcm+lcm)%lcm;//使解在0~lcm[a1,a2,a3...an]之内
            printf("%I64d\n",ans);
        }
    }
    return 0;
}


你可能感兴趣的:(POJ 2891 Strange Way to Express Integers(一元线性同余方程组模版题))