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


    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;
    }
    
    

    能力有限 有误之处请指正


    齐芒行,川锋明!
  • 相关阅读:
    树链剖分(转载)
    随机数生成器
    错排公式的理解与推导(转载)
    容斥原理(转载)
    Luogu 3758 [TJOI2017]可乐(有向图邻接矩阵幂的意义 矩阵快速幂)
    vue input复选框checkbox默认样式纯css修改
    vue 页面切换的时候vuex记录之前的滚动条位置
    vue从入门到进阶
    es6 学习笔记
    vue 项目笔记
  • 原文地址:https://www.cnblogs.com/qimang-311/p/13577625.html
Copyright © 2020-2023  润新知