EXCRT

是个好东西,可以处理在模数不互质的同余方程组

核心就是用扩欧来合并方程

如果我们有两个形如\(x\equiv b_1(mod\ a_1)\) \(x\equiv b_2(mod\ a_2)\)的方程我们要将他们合并

就是利用各种操作化柿子

\[x=a_1k_1+b_1=a_2k_2+b_2 \]

随便移一下

\[a_1k_1=b_2-b_1+a_2k_2 \]

根据贝祖定理\((a1,a2)|(b_2-b_1)\)时候才有解

如果有解得话,我们只需要在两边除以\((a1,a2)\)

那么就有

\[\frac{a_1k_1}{(a_1,a_2)}=\frac{b_2-b_1}{(a_1,a_2)}+\frac{a_2k_2}{(a_1,a_2)} \]

我们也可以写成同余的形式

\[\frac{a_1k_1}{(a_1,a_2)}\equiv \frac{b_2-b_1}{(a_1,a_2)}(mod\ \frac{a_2}{(a_1,a_2)}) \]

让左边只留下\(k_1\),就是把逆元乘过去

\[k_1\equiv inv(\frac{a_1}{(a_1,a_2)},\frac{a_2}{(a_1,a_2)})*\frac{b_2-b_1}{(a_1,a_2)}(mod\ \frac{a_2}{(a_1,a_2)}) \]

再将同余式写成等式

\[k_1=inv(\frac{a_1}{(a_1,a_2)},\frac{a_2}{(a_1,a_2)})*\frac{b_2-b_1}{(a_1,a_2)}+\frac{a_2}{(a_1,a_2)}*y \]

再回带到\(x\)里去

\[x=inv(\frac{a_1}{(a_1,a_2)},\frac{a_2}{(a_1,a_2)})*\frac{b_2-b_1}{(a_1,a_2)}*a_1+\frac{a_2a_1}{(a_1,a_2)}*y+b_1 \]

现在我们再写成同余式

\[x\equiv inv(\frac{a_1}{(a_1,a_2)},\frac{a_2}{(a_1,a_2)})*\frac{b_2-b_1}{(a_1,a_2)}*a_1\%\frac{a_2}{(a_1,a_2)}+b_1(mod\ \frac{a_1a_2}{(a_1,a_2)}) \]

现在两个方程不就被合并好了吗

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 100005
#define LL long long
LL x,y;
LL gcd(LL a,LL b)
{
    if(!b) return a;
    return gcd(b,a%b);
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b) return x=1,y=0,a;
    LL r=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return r;
}
int n;
LL a[maxn],b[maxn];
inline LL read()
{
    char c=getchar();
    LL x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
inline LL inv(LL a,LL b)
{
    LL r=exgcd(a,b,x,y);
    LL t=b/r;
    return (x%t+t)%t;
}
inline LL mul(LL a,LL b)
{
    LL S=0;
    while(b)
    {
        if(b&1ll) S=S+a;
        b>>=1ll;
        a=a+a;
    }
    return S;
}
void write(LL x)
{
	if(x>9) write(x/10);
	putchar(x%10+48);
}
int main()
{
    n=read();
    for(re int i=1;i<=n;i++)
        a[i]=read(),b[i]=read();
    LL r=gcd(a[1],a[2]);
    LL A=mul(a[1],a[2]/r);
    LL B=(inv(a[1]/r,a[2]/r)*(b[2]-b[1])/r%(a[2]/r)+a[2]/r)%(a[2]/r)*a[1]+b[1];
    for(re int i=3;i<=n;i++)
    {
        LL r=gcd(A,a[i]);
        B=(inv(A/r,a[i]/r)*(b[i]-B)/r%(a[i]/r)+a[i]/r)%(a[i]/r)*A+B;
        A=mul(A,a[i]/r);
    }
    write(B);
    return 0;
}
posted @ 2019-01-02 12:12  asuldb  阅读(183)  评论(0编辑  收藏  举报