zoukankan      html  css  js  c++  java
  • [扩展中国剩余定理(EXCRT)]

    前言

    进入正题


    题目描述

    给定 $n$ 组 非负整数 $$a_i,b_i$$,求解关于 $x$ 的方程组

                $x ≡ a_1 (mod~b_1)$

                $x ≡ a_2 (mod~b_2)$

                $.$

                $.$

                $x ≡ a_n (mod~b_n)$

    声明 : $M$ 表示 前 $i-1$ 个$b_i$ 的 最小公倍数$(LCM)$, $ans$ 表示 满足前 $i-1 $个方程的最小解

    初始化: 特判 第一组方程 令 $M = b_1 , ans = a_1$(第一组的话 $b_1$的最小公倍数就是自己,只看第一个方程 $ans$ 就等于 $a_1$)

    从第二组开始:

            $LCM(b_1,b_2) =  frac{b_1×b_2}{gcd(b_1,b_2)}$这个不需要证明

            因为 此时 $M = b_1$ ,所以原式可化为:

                     $LCM(M,b_2) =  frac{M×b_2}{gcd(M,b_2)}$

    考虑: $ans + t×M$ 一定是 前 $i-1$ 个方程 的通解,因为 $ans$ 是 最小解 所以 $ans$ 加上前 $i-1$ 个方程 $b_i$ 的最小公倍数 一定是前 $i-1$ 个方程 的通解。(其中 $t ∈ Z$)

    所以 如果要使得 $ans$ 也满足 下一个方程的话(以第二个 来举例):

        $ans + t×M ≡ a_2 (mod~b_2)$ 此时 $ans$ 是$a_1$ 是已知的

    移项得 : $t×M ≡ a_2 - ans (mod~b_2)$(这一看就是 扩展欧几里得)($ax ≡ c (mod~b)$)

    所以 此时 $t$ 就相当于是 $x$ ,$M$ 相当于是$a$ ,$a_2 - ans$ 就相当于是$c$

    所以利用扩展欧几里得 可以 解得$t$

    但是 我们 要考虑 一个问题 扩展欧几里得 的操作

    也就是说 我们解得的$t$ 其实是

    $t×M ≡ gcd(M,b_2)~(mod~b_2)$的解

    所以 $a_2 - ans$ 到 $gcd(M,b_2)$ 相当于是乘了一个 $frac{gcd(M,b_2)}{a_2 - ans}$ 所以我们得到的解 也相当于是 乘了 一个$frac{gcd(M,b_2)}{a_2 - ans}$

    那么真正的 t 应该是 $frac{t}{frac{gcd(M,b_2)}{a_2 - ans}}$

    也就是 $t ×frac{a_2 - ans}{gcd(M,b_2)}$

    那么 对于下一次 求解来说 

    更新答案 : $ans = ans + t × M$,然后 $ans = (ans~mod~M + M)~mod~M$ 保证$ans$ 是最小的正整数解

      然后因为 $$LCM(M,b2) =  frac{M×b_2}{gcd(M,b_2)}$$ 所以更新$M$ $$M *= frac{b_2}{gcd(M,b_2)}$$。

    同理 循环 $n - 1$ 次 得到最小的 $ans$ 也就是要求的 $x$

    下面贴代码

    #include <cstdio>
    #include <cctype>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long LL;
    
    const int maxn = 100005;
    
    int n;
    
    
    LL ai[maxn],bi[maxn];
    
    LL quickmul(LL a,LL b,LL mod)// 这是龟速乘 
    {
        LL res = 0;
        
        while(b)
        {
            if(b & 1) res = (res + a) % mod;
            
            a = (a + a) % mod;
            b >>= 1; 
        }
        
        return res % mod;
    }
    
    LL exGcd(LL a,LL b,LL &x,LL &y)// 扩欧 
    {
        if(!b)
        {
            x = 1;
            y = 0;
            return a;
        }
        
        LL r = exGcd(b,a%b,x,y);
        
        LL t = x; x = y; y = t - a/b * y;
        
        return r;
    }
    
    LL exCrt()
    {
        LL x,y;
        
        LL M = bi[1], ans = ai[1];//  特判 第一组 解 
        
        for(int i=2;i<=n;i++)
        {
            LL a = M, b = bi[i], c = (ai[i] - ans % b + b) % b;// a*x ≡ c (mod b) 
            
            LL gcd = exGcd(a,b,x,y);
            
            x = quickmul(x,c/gcd,b/gcd);// 相当于 x *= c/gcd 
            
            ans += x * M;
            
            M *= (b / gcd);
            
            ans = (ans % M + M) % M;// 找最小的ans 
        }
        
        return (ans % M + M) % M;
    }
    
    int main()
    {
        scanf("%d",&n);
        
        for(int i=1;i<=n;i++)
            scanf("%d%d",&bi[i],&ai[i]);
            
        printf("%lld",exCrt());
        
        return 0;
    }

     

  • 相关阅读:
    马虎的算式
    jquery中的toggle与slideToggle的区别
    Eclipse下配置C/C++开发环境
    A ResourcePool could not acquire a resource from its primary factory or source
    hadoop mapreduce数据排序
    排序算法之选择排序
    Poj1816(Trie+DFS)
    [置顶] Android4.0 Launcher源码研究
    java第十五天_Map集合,
    VirtualBox下安装ubuntu server 16.04
  • 原文地址:https://www.cnblogs.com/-Wind-/p/10705070.html
Copyright © 2011-2022 走看看