[数论第二节]欧拉函数/快速幂/扩展欧几里得算法

  • 欧拉函数

    • 欧拉函数 φ ( N ) \varphi(N) φ(N) : 1-N中与N互质的数的个数
    • N = p 1 a 1 ⋅ p 2 a 2 ⋅ p 3 a 3 ⋅ ⋅ ⋅ ⋅ p n a n N = p_1^{a_1} · p_2^{a_2} · p_3^{a_3} ··· ·p_n^{a_n} N=p1a1p2a2p3a3⋅⋅⋅⋅pnan 其中p为N的所有质因子
    • φ ( N ) = N ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋅ ⋅ ⋅ ( 1 − 1 p n ) \varphi(N) = N(1-\frac{1}{p_1})(1-\frac{1}{p_2})···(1-\frac{1}{p_n}) φ(N)=N(1p11)(1p21)⋅⋅⋅(1pn1)
    • 证明:
      • 互质:两数的公共因子只有1
      • 去掉所有与N有(大于1的)公共因子的数,剩下的数就是与N互质的数
      • 对N的所有质因子 p k p_k pk,去掉所有 质数 p k 的倍数 ‾ \underline{质数p_k的倍数} 质数pk的倍数(与N有公共因子的数), 每个质数的倍数 ‾ \underline{每个质数的倍数} 每个质数的倍数个数为 N p k \frac{N}{p_k} pkN,即 N − N p 1 − N p 2 − ⋅ ⋅ ⋅ − N p n N - \frac{N}{p_1} - \frac{N}{p_2} - ··· -\frac{N}{p_n} Np1Np2N⋅⋅⋅pnN
      • 对于数 p i ⋅ p j p_i·p_j pipj,在去掉 p i p_i pi 的倍数和去掉 p j p_j pj 的倍数的过程中去除了两次,所以要加上一次,即 N − ( N p 1 + N p 2 + ⋅ ⋅ ⋅ + N p n ) + ( N p 1 p 2 + N p 1 p 3 + ⋅ ⋅ ⋅ + N p n − 1 p n ) N - (\frac{N}{p_1} + \frac{N}{p_2} + ··· +\frac{N}{p_n}) + (\frac{N}{p_1p_2} + \frac{N}{p_1p_3} + ··· +\frac{N}{p_{n-1}p_n}) N(p1N+p2N+⋅⋅⋅+pnN)+(p1p2N+p1p3N+⋅⋅⋅+pn1pnN)
      • 对于数 p i ⋅ p j ⋅ p k p_i·p_j·p_k pipjpk,在去掉 p k p_k pk的倍数的过程中被去掉了三次,在加上合数 p i ⋅ p j p_i·p_j pipj 的过程中被加上了三次,所以合数 p i ⋅ p j ⋅ p k p_i·p_j·p_k pipjpk 没有被去掉,因此要去掉它,即 N − ( N p 1 − N p 2 − ⋅ ⋅ ⋅ − N p n ) + ( N p 1 p 2 + N p 1 p 3 + ⋅ ⋅ ⋅ + N p n − 1 p n ) − ( N p 1 p 2 p 3 + N p 1 p 2 p 4 + ⋅ ⋅ ⋅ + N p n − 2 p n − 1 p n ) N - (\frac{N}{p_1} - \frac{N}{p_2} - ··· -\frac{N}{p_n}) + (\frac{N}{p_1p_2} + \frac{N}{p_1p_3} + ··· +\frac{N}{p_{n-1}p_n}) - (\frac{N}{p_1p_2p_3} + \frac{N}{p_1p_2p_4} + ··· +\frac{N}{p_{n-2}p_{n-1}p_n}) N(p1Np2N⋅⋅⋅pnN)+(p1p2N+p1p3N+⋅⋅⋅+pn1pnN)(p1p2p3N+p1p2p4N+⋅⋅⋅+pn2pn1pnN)
      • 对于合数 p i ⋅ p j ⋅ p k ⋅ p m p_i·p_j·p_k·p_m pipjpkpm 同理,归纳递推可知,所有质数个数为: N − ∑ i = 1 n N p i + ∑ 1 < = i < j < = n N p i p j − ∑ 1 < = i < j < k < = n N p i p j p k + ⋅ ⋅ ⋅ + ( − 1 ) 2 n − 1 ∑ 1 < = i < j < k < ⋅ ⋅ ⋅ < = n N p i p j p k ⋅ ⋅ ⋅ p N - \displaystyle\sum^n_{i=1}{\frac{N}{p_i}}+\displaystyle \sum_{1<=i<j<=n}{\frac{N}{p_ip_j}}-\displaystyle \sum_{1<=i<j<k<=n}{\frac{N}{p_ip_jp_k}}+···+(-1)^{2n-1}\displaystyle \sum_{1<=i<j<k<···<=n}{\frac{N}{p_ip_jp_k···p}} Ni=1npiN+1<=i<j<=npipjN1<=i<j<k<=npipjpkN+⋅⋅⋅+(1)2n11<=i<j<k<⋅⋅⋅<=npipjpk⋅⋅⋅pN
      • 同样基于容斥原理:
        • ∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣ |A\cup B\cup C|=|A|+|B|+|C|-|A\cap B|-|A\cap C|-|B\cap C|+|A\cap B\cap C| ABC=A+B+CABACBC+ABC
        • ∣ ∪ i = 1 n A i ∣ = ∑ i ∣ A i ∣ − ∑ i , j ∣ A i ∩ A j ∣ + … + ( − 1 ) n + 1 ∣ ∩ i = 1 n A i ∣ |\displaystyle \cup_{i=1}^n A_i |=\sum_{i}|A_i|-\sum_{i,j} |A_i \cap A_j|+\ldots +(-1)^{n+1}|\cap_{i=1}^n A_i | i=1nAi=iAii,jAiAj++(1)n+1i=1nAi
        • 与N有(大于1的)公共因子的个数 =| p i p_i pi 的倍数的个数| - | p i p j p_ip_j pipj 的倍数的个数| + | p i p j p k p_ip_jp_k pipjpk 的倍数的个数 ··· ( − 1 ) n + 1 (-1)^{n+1} (1)n+1 | p i p j ⋅ ⋅ ⋅ p n p_ip_j···p_n pipj⋅⋅⋅pn 的倍数的个数|
      • 将上式因式分解后: N ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋅ ⋅ ⋅ ( 1 − 1 p n ) N(1-\frac{1}{p_1})(1-\frac{1}{p_2})···(1-\frac{1}{p_n}) N(1p11)(1p21)⋅⋅⋅(1pn1)
    • 容斥原理:
      int res = a;
      for(int i = 2; i <= a / i; ++ i){
          if(a % i == 0){//i为质因子
              res = res / i * (i - 1);//套公式
              while(a % i == 0) a /= i;//把因子除干净
          }
      }
      if(a > 1) res = res / a * (a - 1);//最后一个因子可能大于sqrt(a)
      
    • 筛选法:
      • 利用线性筛选质数的过程求出每个数的欧拉函数
      • 欧拉函数为积性函数,当a与b互质时有 φ ( a ⋅ b ) = φ ( a ) ⋅ φ ( b ) \varphi(a·b)=\varphi(a)·\varphi(b) φ(ab)=φ(a)φ(b)
      • i为质数时, φ ( i ) = i − 1 \varphi(i)=i-1 φ(i)=i1
      • i p j = 0 \frac{i}{p_j} = 0 pji=0时, p j p_j pj为i的质因子,此时 p j ⋅ i p_j·i pji的质因子与i的质因子完全相同,所以 φ ( p j ⋅ i ) = p j ⋅ i ⋅ ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋅ ⋅ ⋅ ( 1 − 1 p n ) = p j ⋅ φ ( i ) \varphi(pj·i)=pj·i·(1-\frac{1}{p_1})(1-\frac{1}{p_2})···(1-\frac{1}{p_n})=p_j·\varphi(i) φ(pji)=pji(1p11)(1p21)⋅⋅⋅(1pn1)=pjφ(i)
      • i p j ≠ 0 \frac{i}{p_j} \neq 0 pji=0时, p j p_j pj不为i的质因子,此时 p j ⋅ i p_j·i pji的质因子比i的质因子多一个 p j p_j pj,所以 φ ( p j ⋅ i ) = p j ⋅ i ⋅ ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋅ ⋅ ⋅ ( 1 − 1 p n ) ( 1 − 1 p j ) = p j ⋅ φ ( i ) ⋅ ( 1 − 1 p j ) = ( p j − 1 ) ⋅ φ ( i ) \varphi(pj·i)=pj·i·(1-\frac{1}{p_1})(1-\frac{1}{p_2})···(1-\frac{1}{p_n})(1-\frac{1}{p_j})=p_j·\varphi(i)·(1-\frac{1}{p_j})=(p_j - 1)·\varphi(i) φ(pji)=pji(1p11)(1p21)⋅⋅⋅(1pn1)(1pj1)=pjφ(i)(1pj1)=(pj1)φ(i)
      • 代码:
        const int N = 1e6 + 10;
        typedef long long LL;
        int primes[N], cnt;//质数数组,下标
        int st[N];//标记为合数
        int phi[N];//欧拉函数
        int n;
        
        LL get_eulers(int n){
            phi[1] = 1;
            for(int i = 2; i <= n; ++ i){
                if(!st[i]){
                    primes[ ++ cnt] = i;
                    phi[i] = i - 1;//质数i的欧拉函数为i - 1
                }
                for(int j = 1; primes[j] <= n / i; ++ j){
                    int pj = primes[j];
                    st[pj * i] = 1;
                    if(i % pj == 0){//i是合数
                        phi[pj * i] = pj * phi[i];//pj为i的质因子
                        break;
                    }
                    else phi[pj * i] = (pj - 1) * phi[i];//pj不是i的因子
                }
            }
            
            LL ans = 0;
            for(int i = 1; i <= n; ++ i) ans += phi[i];
            return ans;
        }
        
    • 欧拉函数的应用

      • 欧拉定理
        • a与n互质,则 a φ ( n ) ( m o d n ) ≡ 1 a^{\varphi(n)}\pmod n\equiv1 aφ(n)(modn)1
        • 证明:
          • 若a与b互质,且 a ( m o d b ) ≠ 0 a\pmod b\neq 0 a(modb)=0 a ( m o d b ) a\pmod b a(modb) 也与b互质
          • a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a φ ( n ) a_1,a_2,a_3···a_{\varphi(n)} a1,a2,a3⋅⋅⋅aφ(n) 为1~n中的所有与n互质的数
          • 每个数同时乘上a得 a ⋅ a 1 , a ⋅ a 2 , a ⋅ a 3 ⋅ ⋅ ⋅ a ⋅ a φ ( n ) a·a_1,a·a_2,a·a_3···a·a_{\varphi(n)} aa1,aa2,aa3⋅⋅⋅aaφ(n) 由于a也与n互质,所以乘a后所得的数也全部与n互质
          • 将每个数mod n,取模后的每个数都在1~n范围内,并且仍然都与n互质,显然取模后的这几个数就是原来的几个数,只不过数的顺序可能发生了变化
          • 将所有数相乘,则有 a ⋅ a 1 ⋅ a ⋅ a 2 ⋅ a ⋅ a 3 ⋅ ⋅ ⋅ a ⋅ a φ ( n ) ( m o d n ) = a 1 ⋅ a 2 ⋅ a 3 ⋅ ⋅ ⋅ a φ ( n ) a·a_1·a·a_2·a·a_3···a·a_{\varphi(n)} \pmod n=a_1·a_2·a_3···a_{\varphi(n)} aa1aa2aa3⋅⋅⋅aaφ(n)(modn)=a1a2a3⋅⋅⋅aφ(n)
          • 所以有: a φ ( n ) ⋅ ( a 1 a 2 a 3 ⋅ ⋅ ⋅ a φ ( n ) ) ( m o d n ) ≡ ( a 1 ⋅ a 2 ⋅ a 3 ⋅ ⋅ ⋅ a φ ( n ) ) a^{\varphi(n)}·(a_1a_2a_3···a_{\varphi(n)})\pmod n \equiv (a_1·a_2·a_3···a_{\varphi(n)}) aφ(n)(a1a2a3⋅⋅⋅aφ(n))(modn)(a1a2a3⋅⋅⋅aφ(n)) a φ ( n ) ( m o d n ) ≡ 1 a^{\varphi(n)}\pmod n\equiv1 aφ(n)(modn)1
          • 特别地,当n为质数时, a n − 1 ( m o d n ) ≡ 1 a^{n-1}\pmod n\equiv1 an1(modn)1 为费马定理
  • 快速幂

    • 快速地求出 a k ( m o d b ) a^k\pmod b ak(modb),时间复杂度为== O ( l o g ( k ) ) O(log(k)) O(log(k))==
    • 将k拆分为二进制相加,即
    • k = c 1 ⋅ 2 1 + c 2 ⋅ 2 2 + c 3 ⋅ 2 3 + ⋅ ⋅ ⋅ + c n ⋅ 2 n k=c_1·2^1+c_2·2^2+c_3·2^3+···+c_n·2^n k=c121+c222+c323+⋅⋅⋅+cn2n
    • 其中 c i c_i ci 是k的二进制的每一位(0/1),n最大为k的二进制的位数
    • 所以
    • a k ( m o d b ) = a c 1 ⋅ 2 1 + c 2 ⋅ 2 2 + c 3 ⋅ 2 3 + ⋅ ⋅ ⋅ + c n ⋅ 2 n ( m o d b ) = a c 1 ⋅ 2 1 ⋅ a c 2 ⋅ 2 2 ⋅ a c 3 ⋅ 2 3 ⋅ ⋅ ⋅ a c n ⋅ 2 n ( m o d b ) a^k\pmod b=a^{c_1·2^1+c_2·2^2+c_3·2^3+···+c_n·2^n} \pmod b=a^{c_1·2^1}·a^{c_2·2^2}·a^{c_3·2^3}···a^{c_n·2^n} \pmod b ak(modb)=ac121+c222+c323+⋅⋅⋅+cn2n(modb)=ac121ac222ac323⋅⋅⋅acn2n(modb)
    • 所以每次遍历k的所有二进制位,同时预处理出 a i a^i ai,根据k的二进制的取值将答案累乘
    • 代码:
      typedef long long LL;
      //求a^k mod b
      int qmi(int a, int k, int b){
      	int res = 1;
      	while(k){
      		if(k & 1) res = (LL)res * a % b;//k的当前位非0,则将a累乘到答案
      		k >>= 1;//k右移一位
      		a = (LL)a * a % b;//a的幂倍增
      	}
      	return res;
      }
      
    • 快速幂求逆元
      • b与p互质,且 b ∣ a b|a ba a b = a ⋅ x ( m o d p ) \frac a b=a·x \pmod p ba=ax(modp) ,则x为b的逆元
      • 两边乘b有 a = a ⋅ b ⋅ x ( m o d p ) a=a·b·x \pmod p a=abx(modp)
      • 所以有 b ⋅ x = 1 ( m o d p ) b·x=1 \pmod p bx=1(modp)
      • 若p是质数,有费马定理 b p − 1 = 1 ( m o d p ) b^{p-1} = 1 \pmod p bp1=1(modp) x = b p − 2 x=b^{p-2} x=bp2
      • 若p不是质数,有欧拉定理 b φ ( p ) = 1 ( m o d p ) b^{\varphi(p)}=1 \pmod p bφ(p)=1(modp) x = b φ ( p ) − 1 x=b^{\varphi(p)- 1} x=bφ(p)1
      • 代码:
        int qmi(int a, int b, int p){...
        }
        if(b与q互质){ //互质是有解的前提
        	if(p为质数) cout << qmi(b, p - 2, p);
        	else cout << qmi(b, phi[p] - 1, p);
        }else 无解
        
  • 扩展欧几里得定理

    • 裴蜀定理:对于任意正整数a,b, 都一定存在整数x,y, 使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b), 并且 g c d ( a , b ) gcd(a,b) gcd(a,b) 一定是a与b能构造出来的最小公约数

    • 扩展欧几里得算法就是求这样的x,y

    • 用于求解方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 的解

    • b = 0 b=0 b=0 a x + b y = a ax+by=a ax+by=a 故而 x = 1 , y = 0 x=1,y=0 x=1,y=0

    • b ≠ 0 b \neq 0 b=0 时,因为

    • g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a \% b) gcd(a,b)=gcd(b,a%b)

    • b ⋅ x 1 + ( a % b ) ⋅ y 1 = g c d ( b , a % b ) b·x_1+(a \% b)·y_1 = gcd(b,a\%b) bx1+(a%b)y1=gcd(b,a%b)

    • b ⋅ x 1 + ( a − ⌊ a / b ⌋ ⋅ b ) ⋅ y 1 = g c d ( b , a % b ) b·x_1+(a-\lfloor a/b \rfloor · b)·y_1=gcd(b,a\%b) bx1+(aa/bb)y1=gcd(b,a%b)

    • a y 1 + b ⋅ ( x 1 − ⌊ a / b ⌋ ) = g c d ( b , a % b ) = g c d ( a , b ) ay_1+b·(x_1-\lfloor a/b \rfloor)=gcd(b,a\%b)=gcd(a,b) ay1+b(x1a/b⌋)=gcd(b,a%b)=gcd(a,b)

    • 故而 x = y 1 , y = x 1 − ⌊ a / b ⌋ ⋅ y 1 x=y_1,\quad y=x_1-\lfloor a/b \rfloor ·y_1 x=y1,y=x1a/by1

    • 代码:

      int exgcd(int a, int b, int &x, int &y){
          if(!b){ //b = 0时,ax + by = gcd(a, 0) = a,所以x = 1, y = 0;
              x = 1, y = 0;
              return a;
          }else {
              int d = exgcd(b, a % b, x, y);//交换a与b,x与y
              int t = x;
              x = y;//x1 = y2
              y = t - a / b * y;//y1 = x2 - a / b * y2
              return d;
          }
      }
      
      //简化版
      void exgcd(int a, int b, int &x, int &y){
          if(!b){
              x = 1, y = 0;
              return a;
          }else{
      	    int d = exgcd(b, a % b, y, x);
      	    y -= a / b * x;
      	    return d;
          }    
      }
      
    • 扩展欧几里得求解线性同余方程
      • 线性同余方程: a x ≡ b ( m o d m ) ax \equiv b \pmod m axb(modm) 其中a,x,b,m均为整数,x为未知数,方程等价于 a x = k m + b ax=km+b ax=km+b,也等价于 a x + m k = b ax+mk=b ax+mk=b其中x,k均为未知数
      • 方程形如: a x + b y = c ax+by=c ax+by=c 的直线方程,解(x,y)为直线上散列的点
      • 求出a,b的最大公约数 d = g c d ( a , b ) d = gcd(a,b) d=gcd(a,b),方程化为 d ( x a d + y b d ) = c d(x \frac a d+y\frac b d)=c d(xda+ydb)=c易知其中 x a d + y b d x \frac a d+y\frac b d xda+ydb 为整数,所以要求 d ∣ c d|c dc,故 c = k ⋅ d = k ⋅ g c d ( a , b ) c=k·d=k·gcd(a,b) c=kd=kgcd(a,b)
      • 所以线性同余方程 a x ≡ b ( m o d m ) ax \equiv b \pmod m axb(modm)有解的充要条件为b为 g c d ( a , m ) gcd(a,m) gcd(a,m)的倍数
      • b ≠ k ′ ⋅ g c d ( a , m ) b \neq k'·gcd(a,m) b=kgcd(a,m) 时( k ′ k' k 为整数),方程无解
      • b = k ′ ⋅ g c d ( a , m ) b = k'·gcd(a,m) b=kgcd(a,m) 时,先用扩展欧几里得求出方程 a x + m k = g c d ( a , m ) ax+mk=gcd(a,m) ax+mk=gcd(a,m) 的特解 ( x , k ) (x,k) (x,k),可知 a x + m k = b ax+mk=b ax+mk=b 方程的解为 b g c d ( a , m ) ⋅ ( x , k ) \frac {b}{gcd(a,m)}·(x,k) gcd(a,m)b(x,k) ,所以原式的解为 b g c d ( a , m ) ⋅ x \frac {b}{gcd(a,m)}·x gcd(a,m)bx
      • 代码:
        const int N = 1e5 + 10;
        typedef long long LL;
        int n; 
        int a, b, m;
        int x, y;
        //扩展欧几里得算法
        int exgcd(int a, int b , int &x, int &y){
            if(!b){
                x = 1, y = 0;
                return a;
            }else{
                int t = exgcd(b, a % b, y, x);
                y -= a / b * x;
                return t;
            }
        }
        
        int main(){
            cin >> n;
            while(n -- ){
                cin >> a >> b >> m;
                int t = exgcd(a, m, x, y);
                //b是gcd(a,m)的倍数才有解
                if(b % t != 0) cout << "impossible" << endl;
                else cout << (LL)x * (b / t) % m << endl;//特解乘上倍数
            }
            return 0;
        }
        
  • 中国剩余定理

    • 中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中 n 1 , n 2 , n 3 , ⋅ ⋅ ⋅ n k n_1,n_2,n_3,···n_k n1,n2,n3,⋅⋅⋅nk 两两互质):
    • { x ≡ a 1 ( m o d n 1 ) x ≡ a 2 ( m o d n 2 ) ⋮ x ≡ a k ( m o d n k ) \begin{cases} x &\equiv a_1 \pmod {n_1} \\ x &\equiv a_2 \pmod {n_2} \\ &\vdots \\ x &\equiv a_k \pmod {n_k} \\ \end{cases} xxxa1(modn1)a2(modn2)ak(modnk)
    • 过程:
      • 计算所有模数的积
      • 对于第 i i i 个方程:
        • 计算 m i = n n i m_i=\frac{n}{n_i} mi=nin
        • 计算 m i m_i mi 在模 n i n_i ni 意义下的逆元 m i − 1 m^{-1}_i mi1
        • 计算 c i = m i m i − 1 c_i=m_im^{-1}_i ci=mimi1 (不要对 n i n_i ni 取模)
      • 方程组在模 n n n 意义下的唯一解为: x = ∑ i = 1 k a i c i ( m o d n ) x=\sum^{k}_{i=1}a_ic_i \pmod n x=i=1kaici(modn)
    • 扩展版中国剩余定理:
      • 不满足 n 1 , n 2 , n 3 , ⋅ ⋅ ⋅ n k n_1,n_2,n_3,···n_k n1,n2,n3,⋅⋅⋅nk 两两互质时,求解线性同余方程组
      • ① x ≡ a 1 ( m o d n 1 ) ⇔ x = k 1 n 1 + a 1 ①\quad x\equiv a_1\pmod {n_1} \Leftrightarrow x=k_1n_1+a_1 xa1(modn1)x=k1n1+a1
      • ② x ≡ a 2 ( m o d n 2 ) ⇔ x = k 2 n 2 + a 2 ②\quad x \equiv a_2\pmod {n_2} \Leftrightarrow x=k_2n_2+a_2 xa2(modn2)x=k2n2+a2
      • 由①②知 k 1 n 1 + a 1 = k 2 n 2 + a 2 k_1n_1+a_1=k_2n_2+a_2 k1n1+a1=k2n2+a2
      • 移项 k 1 n 1 − k 2 n 2 = a 2 − a 1 k_1n_1-k_2n_2=a_2-a_1 k1n1k2n2=a2a1
      • 其中 n 1 , n 2 , a 2 , a 1 n_1,n_2,a_2,a_1 n1,n2,a2,a1 已知, k 1 , k 2 k_1,k_2 k1,k2 未知,可以用扩展欧几里得算法求出
      • d = a 2 − a 1 g c d ( n 1 , n 2 ) ≠ 0 d=\frac {a_2-a_1}{gcd(n_1,n_2)} \neq 0 d=gcd(n1,n2)a2a1=0 时无解
      • d = a 2 − a 1 g c d ( n 1 , n 2 ) = 0 d=\frac {a_2-a_1}{gcd(n_1,n_2)} = 0 d=gcd(n1,n2)a2a1=0 时,先求出方程
      • k 1 ‘ n 1 − k 2 ‘ n 2 = g c d ( n 1 , n 2 ) k_1^`n_1-k_2^`n_2=gcd(n_1,n_2) k1n1k2n2=gcd(n1,n2)
      • 的特解,求出 k 1 ‘ , k 2 ‘ k_1^`,k_2^` k1,k2
      • k 1 ∗ = k 1 ‘ ⋅ d , k 2 ∗ = k 2 ‘ ⋅ d k_1^*=k_1^`·d,\quad k_2^*=k_2^`·d k1=k1d,k2=k2d
      • 此时 k 1 ∗ , k 2 ∗ k_1^*,k_2^* k1,k2 就是原方程的特解
      • 观察原方程可知通解为
      • k 1 = k 1 ∗ + k ⋅ n 2 d , k 2 = k 2 ∗ + k ⋅ n 1 d ( 其中 k 为整数 ) k_1=k_1^*+k·\frac{n_2}{d},\quad k_2=k_2^*+k·\frac{n_1}{d}(其中k为整数) k1=k1+kdn2,k2=k2+kdn1(其中k为整数)
      • 将通解代入①式得
      • x = ( k 1 ∗ + k ⋅ n 2 d ) n 1 + a 1 = ( k 1 ∗ n 1 ) + a 1 + k ⋅ n 1 n 2 d = ( k 1 ∗ n 1 ) + a 1 + k ⋅ l c m ( n 1 , n 2 ) x=(k_1^*+k·\frac{n_2}{d})n_1+a_1=(k_1^*n_1)+a_1+k·\frac{n_1n_2}{d}=(k_1^*n_1)+a_1+k·lcm(n_1,n_2) x=(k1+kdn2)n1+a1=(k1n1)+a1+kdn1n2=(k1n1)+a1+klcm(n1,n2)
      • 所以
      • ③③ x = k ⋅ l c m ( n 1 , n 2 ) + ( k 1 ∗ n 1 ) + a 1 ③③\quad x=k·lcm(n_1,n_2)+(k_1^*n_1)+a_1 ③③x=klcm(n1,n2)+(k1n1)+a1
      • 其中 k 1 ∗ , n 1 , a 1 , l c m ( n 1 , n 2 ) k_1^*,n_1,a_1,lcm(n_1,n_2) k1,n1,a1,lcm(n1,n2) 已知, k k k 未知
      • n 2 ‘ = l c m ( n 1 , n 2 ) , a 2 ‘ = ( k 1 ∗ n 1 ) + a 1 n_2^`=lcm(n_1,n_2),\quad a_2^`=(k_1^*n_1)+a_1 n2=lcm(n1,n2),a2=(k1n1)+a1 所以③式化为
      • ③ x = k ⋅ n 2 ‘ + a 2 ‘ ③\quad x=k·n_2^`+a_2^` x=kn2+a2
      • 所以将①②式合并后的③式仍与方程组方程相似,于是可以循环将方程组合并为一个式子,通过最后一个式子即可用扩展欧几里得算法求出x
      • 代码:
        const int N = 30;
        typedef long long LL;
        int n;
        
        LL exgcd(LL a, LL b, LL &x, LL &y){
            if(!b){
                x = 1, y = 0;
                return a;
            }
            LL d = exgcd(b, a % b, y, x);
            y -= a / b * x;
            return d;
        }
        int main(){
            cin >> n;
            LL a1, m1;
            bool flag = true;
            cin >> a1 >> m1;//用于存储更新的a与m
            
            for(int i = 1; i < n; ++ i){ //合并n-1次
                LL an, mn;//接受新的a与m
                LL k1, k2; //存储用欧几里得求的系数
                cin >> an >> mn;
                LL d = exgcd(a1, an, k1, k2); //求出gcd(a1, an)以及系数k1, k2
                if((mn - m1) % d){ //无解判断
                    flag = false;
                    break;
                }
                LL t = an / d; //通解k1 = k1 + k * (an / d), k2 = k2 + k * (a1 / d),题目为了求最小的x,故要让k1为最小解故要k1不断膜上t
                k1 = k1 * (mn - m1) / d; //更新k1
                k1 = (k1 % t + t) % t; //取k1的最小解
                m1 = k1 * a1 + m1; //m更新为k1 * a1 * m1
                a1 = abs(a1 / d * an);  //a1更新为gcd(a1, an)
            }
            
            if(flag){
                cout << (m1 % a1 + a1) % a1; //最后一个式子的就是余数m
            }else cout << -1;
            return 0;
        }
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值