模板:拓展中国剩余定理

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/82901942

设有n个式子。

 \begin{cases} & x\equiv c1\ (mod \ \ b1)\\ & x\equiv c2\ (mod \ \ b2)\\ & x\equiv c3\ (mod \ \ b3)\\ & x\equiv c4\ (mod \ \ b4) \end{cases}

然后当前进行到了这样。第一个式子表示它之前所有式子的集合,第二个是新来的式子。

\begin{cases} & x\equiv c1\ (mod \ \ b1)\\ & x\equiv c2\ (mod \ \ b2)\\ \end{cases}

那么可以转化成

\begin{cases} & x\ = c1\ + b1x1\\ & x\ = c2\ + b2x2\\ \end{cases}

我们希望求得一个x同时满足两个式子。所以可以这样转化两个式子(把x2想象成一个常数,x2倍的b2可以使x满足条件)

那么式子就变成了这样

b1x1+b2x2=c2-c1

这个式子就可以认为是

b1x1\equiv c2-c1 \ (mod \ b2)

利用拓展gcd进行求解可以得到一个解x{}'g为他们的gcd。

那么x1的解集就可以表示为

\frac{c2-c1}{g} \ {x}' + \frac{b2}{g} \ t

然后把x1带回1式得

 x = c1 \ + \ \frac{b1(c2-c1)}{g} {x}'\ +\frac{b1b2}{g} \ t

也就是

x = c1 \ + \ \frac{b1(c2-c1)}{g} {x}'\ ( \ mod \ \frac{b1b2}{g} \ )

所以每一次都以当前的ci减去之前的答案和ans作为新的c,当前的bi作为新的b,之前的b的lcm(简称M)作为新的a

构成拓展gcd求解,也就是ax+by=c

lcm(M,bi)作为模数,按上式得出新的答案(PS:简单的操作就是先把M/g,这样他乘上b或者c都是相应的lcm)

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll b[100005];
ll c[100005];
ll x,y,M,ans;
ll ex_gcd(ll a,ll b)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    ll r=ex_gcd(b,a%b);
    ll t=x;
    x=y;
    y=t-a/b*x;
    return r;
}
ll mul(ll a,ll b,ll mode)
{
    ll s=0;
    while(b)
    {
        if(b%2==1)
        {
            s+=a;
            s%=mode;
        }
        a=(a+a)%mode;
        b=b/2;
    }
    return s;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%lld%lld",&b[i],&c[i]);
    }
    M=b[1],ans=c[1];
    for(int i = 2;i <= n;i++)
    {
        ll aa=M,bb=b[i],cc=c[i]-ans;
        ll gg=ex_gcd(aa,bb);
        if(cc%gg)
        {
            printf("-1");
            return 0;
        }
        M/=gg;M*=bb;//因为推倒得出这次的x前的系数是cc/gg*M也就是只能除下去一次gg 
        x=(x%M+M)%M;
        ans+=mul(mul(M/bb,(cc%M+M)%M,M),x,M)%M;//这也是我多次试验之后发现的结果,这步的乘法必须为cc,M/bb的lcm乘以x,所以写过的bb/gg,cc/gg,但是M没除,也对了,因为最后也是lcm 
		ans=(ans%M+M)%M; 
    }
    printf("%lld",(ans%M+M)%M);
    return 0;
}//最终根据证明,取模的数是M*bb/gg。 

猜你喜欢

转载自blog.csdn.net/zzk_233/article/details/82901942