洛谷 P4777 【模板】扩展中国剩余定理(EXCRT)

233

  • 题目:
  • 题意:
  • 分析:
  • 代码:


题目:

传送门


题意:

{ x ≡ a 1 ( m o d   b 1 ) x ≡ a 2 ( m o d   b 2 ) … … x ≡ a n ( m o d b n ) \left\{\begin{matrix} x\equiv a_1(mod\ b_1) \\ x\equiv a_2(mod\ b_2) \\ ……\\ x\equiv a_n(mod b_n) \end{matrix}\right. xa1(mod b1)xa2(mod b2)xan(modbn)
求解上述式子, b b b不保证互质


分析:

我们的核心思想便是做 n n n e x g c d exgcd exgcd,将上面的方程一个个合并
以前两个式子为例:
我们可以得到 x = a 1 + k 1 ∗ b 1 、 x = a 2 + k 2 ∗ b 2 x=a_1+k_1*b_1、x=a_2+k_2*b_2 x=a1+k1b1x=a2+k2b2
a 1 + k 1 ∗ b 1 = a 2 + k 2 ∗ b 2 a_1+k_1*b_1=a_2+k_2*b_2 a1+k1b1=a2+k2b2
进一步化简得到 b 1 ∗ k 1 − b 2 ∗ k 2 = a 2 − a 1 b_1*k_1-b_2*k_2=a_2-a_1 b1k1b2k2=a2a1
这时我们可以根据 e x g c d exgcd exgcd的引理进行求解
最后需要注意的是,在求 k 1 k_1 k1的通解时会有溢出,所以要不断的进行取模


代码:

#include
#include
#include
#include
#include
#include
#define LL long long 
#define LZX Mu
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
LL a[100005],b[100005];
void exgcd(LL n1,LL n2,LL &g,LL &x,LL &y)
{
    if(!n2) {x=1;y=0;g=n1;return;}
    exgcd(n2,n1%n2,g,x,y);
    int z=x;
    x=y;y=z-y*(n1/n2);
    return;
}
LL ans,m;
LL ksc(LL a,LL b,LL MAR)
{
    a%=MAR;b%=MAR;
    LL c=(long double)a*b/MAR;
    LL ans=a*b-c*MAR;
    if(ans<0) ans+=MAR;
    else if(ans>=MAR) ans-=MAR;
    return ans;
}
void china(LL a1,LL a2,LL b1,LL b2)
{
    LL d=a2-a1;
    LL g,k1,k2;    
    exgcd(b1,b2,g,k1,k2);
    k1=ksc(k1,d/g,b2/g);
    ans+=k1*b1;
    m*=b2/g;    
    ans=(ans%m+m)%m;
    return;
}
int main()
{
    LL n=read();
    for(LL i=1;i<=n;i++) b[i]=read(),a[i]=read();
    ans=a[1],m=b[1];
    for(LL i=2;i<=n;i++)
      china(ans,a[i],m,b[i]);
    cout<<ans;  
    return 0;
} 

你可能感兴趣的:(中国剩余定理)