Fork me on GitHub

【luoguP4777】【模板】扩展中国剩余定理(EXCRT)

(扩展)中国剩余定理

对于一组同余方程

\(x\equiv a_1(mod \quad n_1)\)

\(x\equiv a_2(mod \quad n_2)\)

\(x\equiv a_3(mod \ \ n_3)\)

\(x\equiv a_n(mod\ \ n_m)\)

对于第一个和第二个式子

则有:

\(x = a1 + k1*n1\)

\(x = a2 + k2*n2\)

就有:

\(a1 + k1 * n1 = a2 + k2 * n2\)

\(k1 * n1 - k2 * n2 = a2 - a1\)

故我们设 \(d = a_2 - a_1\) 再变化一下形式就有:

\(k_1 * n_1 + (-k_2) * n_2 = d\)

\(g = gcd(n_1,n_2)\)

这样我们就可以通过exgcd来求出一组解 x1,y1

满足 \(x_1 * n_1 + y_2 * n_2 = g\)

故: \(x_1∗d/g∗n_1+y_2∗d/g∗n_2=g∗d/g\)

则: \(k1=x1∗d/g,k2=y1∗d/g\)

从而得到一组通解

\(k1=k1+n2/g∗T\)

\(k2=k2−n1/g∗T\)

要使所求得的解最小且为正整数则可以根据 k1 的通解形式求得

\(k_1 = ( k_1 % ( n_2/g ) + n_2/g ) % ( n_2/g )\)

再带入 $x=a_1+k_1∗n_1 $得到 xx

令 A 为合并后的 a , N 为合并后的 n

**所以\(N=lcm(n_1,n_2)=n_1∗n_2/g\)

\(x==k_1*p_1+a_1 (mod \ \ lcm(n_1,n_2));\)

void exgcd(ll a,ll b,ll &g,ll &x,ll &y)
{
    if (b == 0)
    {
        g = a;x = 1; y = 0;
        return;
    }
    exgcd(b,a%b,g,y,x);
    y-=(a/b)*x;
}
bool flag = false;
ll a1,a2,n1,n2;
ll abs(ll x) {return x>0?x:-x;} 
void china() 
{
    ll d = a2 - a1;
    ll g,x,y;
    exgcd(n1,n2,g,x,y);
    if (d % g == 0) 
    {
        x = ((x*d/g)%(n2/g)+(n2/g))%(n2/g);
        a1 = x*n1 + a1;
        n1 = (n1*n2)/g;
    }
    else flag = true;
}
int n;
long long as[100001];
long long ps[100001];
ll exchina() 
{
    a1 = as[0];
    n1 =ps[0];
    for (ll i = 1;i<n;i++) 
    {
        a2 = as[i];
        n2 = ps[i];
        china();
        if (flag)
            return -1;
    }
    return a1;
}

int main() 
{ 
    cin>>n;
    flag = false;
    for (ll i = 0;i<n;i++)
        cin>>ps[i]>>as[i];
    cout<<(long long)realchina()<<endl; 
}
posted @ 2019-09-26 19:49  yelir  阅读(227)  评论(1编辑  收藏  举报