扩展中国剩余定理(结合个人理解)

EXCRT(扩展中国剩余定理)

拖更了

此时的模数不一定两两互质,导致了不能直接像之前那样只满足其中一个模数然后依次累加。

所以就只能换其他思路

/*
     不妨来看其中两个条件满足   x=a1+m1*x1     x=a2+m2*x2
     然后直接变换就得到m1*x1-m2*x2=a2-a1   要使得x尽量的小,那么x1和x2都要尽量的小
     根据裴蜀定理  ax+by=c有整数解的充要条件就是(a,b)|c    也就是c是gcd(a,b)的整数倍数
     所以基于此   设g=gcd(m1,m2)
     x1'*m1/g+(-x2'*m2/g)=1  此时的 m1/g=m1'和 m2/g=m2'互质所以此时的gcd(m1',m2')=1此时的(a,b)|c 恒成立
     所以就可以利用扩展欧几里得   对比 x1*m1/g+(-x2*m2/g)=(a2-a1)/g   得到  x1=t*m2'+x1'*(a2-a1)/g   x2=t*m1'+x2'*(a2-a1)/g
     最后直接代入x=a1+m1*x1    得到x=a1+m1*m2'*t+x1'*m1
     最后x等价于(a1+x1'*m1)%(m1*m2')
     (m1*m2')=lcm(m1,m2)
     所以最后我们只需要两个两个联立就可因得到所有的满足条件的x
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+7;
inline int read()
{
    char c = getchar();
    int x = 0,fh = 0;
    while(c < '0' | c > '9'){fh |= c == '-';c = getchar();}
    while(c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}
    return fh?-x:x;
}
#define int long long ///全程开long long    龟速乘都是防止爆long long
int n;
int a[maxn];
int b[maxn];
int  _exgcd(int a,int b,int &x,int &y)///x代表解   扩展欧几里得
{
   if (!b)
   {
     x=1;
     y=0;
     return a ;
   }
   int gcd=_exgcd(b,a%b,x,y);
   int tmp=x;
   x=y;
   y=tmp-(a/b)*y;
   return gcd;///返回最大公约数
}

int gui_sort(int a,int b,int mod)///防止乘法溢出
{
  int ans=0;
  while (b>0)
  {
     if(b&1)
       ans=(ans+a)%mod;///龟速乘 类似于快速幂 就是将a*k拆分成a+2a+4a++。。。。。。
     a=(a+a)%mod;
     b>>=1;
  }
  return ans%mod;
}

int excrt()
{
  int ans=a[1];
  int lcm=b[1];///第一个模数
  int x,y;
  for (int i=2;i<=n;++i)
  {
    int res=(((a[i]-ans)%b[i])+b[i])%b[i];///防止出现负数解    a2-a1
    int gcd=_exgcd(lcm,b[i],x,y);
    int ret=b[i]/gcd;
    if (res%gcd!=0)///不满足裴蜀定理 不存在整数解
      return -1;
    x=gui_sort(x,res/gcd,ret);///x1'*(a2-a1)/gcd
    ans+=x*lcm;///这个就需要自己思考一下了
    ///按照之前的推论是m1也就是第一个模数所以每一次我们只需要乘以第一个模数,越往后模数变成lcm了
    lcm=lcm*ret;///lcm  求取变形之后的模数
    ans=(ans%lcm+lcm)%lcm;///防止出现负数
  }
  return ans;
}
signed main()
{
  n=read();
  for (int i=1;i<=n;++i)
     cin>>b[i]>>a[i];///模数 余数  x=a%b   当时设反了,因为是按照博客来的
  int cnt=excrt();
  printf("%lld
",cnt);
  return 0;
}

能力有限 有误之处请指正


齐芒行,川锋明!
原文地址:https://www.cnblogs.com/qimang-311/p/13577625.html