算法设计与分析学习(6)——数论

数论

整除

  • 基本概念

    • a a a b b b 为整数,且 a ≠ 0 a≠0 a=0
      • 若存在整数 q q q 使得 b = a q b=aq b=aq ,那么就说 a a a 可以整除 b b b 或是 b b b a a a 整除,记作 a ∣ b a|b ab a a a 也被称为 b b b 的约数, b b b 也被称为a的倍数。
      • b b b 不能被 a a a 整除,则记作 a ∤ b a \not{|} b ab
    • 整数 p ≠ 0 , ± 1 p≠0,±1 p=0,±1,且除了 ± 1 , ± p ±1,±p ±1,±p 外没有其他的约数存在,那么p被称之为质数或素数。
      • 没有特殊说明的话,质数(素数)指的是正整数中的质数。
    • 整数 q ≠ 0 , ± 1 q≠0,\pm 1 q=0,±1,且不是质数,那么 q q q 被称之为合数。
      • 没有特殊说明的话,合数指的是正整数中的合数。
    • a , b a,b a,b 是两个整数,若存在整数 d d d d ∣ a d|a da d ∣ b d|b db ,则 d d d 被称为 a a a b b b 的公约数。
      • a , b a,b a,b 两数不全为 0 0 0,则把 a a a b b b 的所有公约数中最大的那个称之为最大公约数,记作 ( a , b ) (a,b) (a,b) g c d ( a , b ) gcd(a,b) gcd(a,b)
      • 同理可以定义公倍数和最小公倍数的概念。 a a a b b b 的最小公倍数记作 [ a , b ] [a,b] [a,b] l c m ( a , b ) lcm(a,b) lcm(a,b)
      • 如果两个数的最大公约数为 1 1 1,则我们称两数互质或互素。
    • a , b a,b a,b 为整数,且 a ≠ 0 a≠0 a=0 。那么一定存在唯一的一对整数 q q q r r r,满足 b = q a + r b=qa+r b=qa+r,其中 0 ≤ r < ∣ a ∣ 0≤r<|a| 0r<a r r r 被称作是 b b b 除以 a a a 的余数,这样的除法运算又被称之为带余除法
  • 性质

    • a ∣ b a|b ab b ∣ c b|c bc ,则有 a ∣ c a|c ac
    • 素数有无穷多个。如果用 π ( x ) π(x) π(x) 表示不超过 x x x 的素数的个数,可以用 $ x/lnx$ 对 π ( x ) π(x) π(x) 进行估计。
    • n n n 为合数,则必有素数 p ∣ n p|n pn ,且 p ≤ π p≤\sqrt{π} pπ
    • ( a , b ) = ( b , a ) (a,b)=(b,a) (a,b)=(b,a) ( a , b , c ) = ( ( a , b ) , c ) = ( a , ( b , c ) ) (a,b,c)=((a,b),c)=(a,(b,c)) (a,b,c)=((a,b),c)=(a,(b,c))
    • [ a , b ] = [ b , a ] [a,b] =[b,a] [a,b]=[b,a] [ a , b , c ] = [ [ a , b ] , c ] = [ a , [ b , c ] ] [a,b,c]=[[a,b],c]=[a,[b,c]] [a,b,c]=[[a,b],c]=[a,[b,c]]
    • ( a , b ) × [ a , b ] = a b (a,b)×[a,b]=ab (a,b)×[a,b]=ab
    • 可以证明,对于任意的整数 a a a b b b,总归存在相应的整数 x x x y y y ,满足 ( a , b ) = a x + b y (a,b)=ax+by (a,b)=ax+by,即 a a a b b b 的最大公约数可以写成 a a a b b b 的线性表示。
    • ( a , b ) = ( r , a ) (a,b)=(r,a) (a,b)=(r,a) 其中 a ≠ 0 a≠0 a=0 r r r b b b 除以 a a a 的余数。
    • n > 1 n>1 n>1,那么 n n n 必存在唯一的质因数分解,即 n = p 1 α 1 p 2 α 2 … p s α s n=p_{1}^{\alpha_1}p_{2}^{\alpha_2}…p_{s}^{\alpha_s} n=p1α1p2α2psαs。其中 p i p_{i} pi 为质数 ( 1 ≤ i ≤ s ) (1≤i≤s) (1is) α i α_i αi 为正整数,且 p i < p i + 1 ( 1 ≤ i < s ) p_ipi<pi+1(1i<s)
      • 正整数 n n n 的正约数的个数(记作 a ( n ) a(n) a(n) )也可以通过 n n n​ 的质因数分解式计算出来。
  • 代码实现

    • 欧几里得除法

      class Int
      {
          int value;
          Int(int v)
          {
              value=v;
          }
      }
      
      public class Euclid 
      {
          static int gcd(int a,int b)
          {
              return b==0 ? a : gcd(b,a%b);
          }
      	
          //利用对象传递参数
          static int extend_gcd(int a,int b,Int x,Int y)
          {
              if(b==0)
              {    
                  x.setValue(1);
                  y.setValue(0);
                  return a;
              }
              else
              {
                  int r=extend_gcd(b,a%b,y,x);
                  y.value-=a/b*x.value;
                  return r;
              }    
          }
      }
      
    • 素数筛

      public class Prime 
      {
          ArrayList<Integer> ans;
          int tot;
          Prime()
          {
              ans=new ArrayList<>();
              tot=0;
          }
      	//复杂度O(NlogN)
          void getPrimeMethodOne(int n)
          {
              boolean[] valid= new boolean[n];
              for(int i=2;i<n;i++)
                  valid[i]=true;
              for(int i=2;i<n;i++)
              {
                  if(n<i*i)
                      break;
                  for(int j=i*i;j<n;j+=i)
                      valid[j]=false;
              }
              for(int i=2;i<n;i++)
                  if(valid[i])
                  {
                      ans.add(i);
                      tot++;
                  }    
          }
      
          //复杂度O(N)
          void getPrimeMethodTwo(int n)
          {
              boolean[] valid= new boolean[n];
              for(int i=0;i<n;i++)
                  valid[i]=true;
              for(int i=2;i<n;i++)
              {
                  if(valid[i])
                  {
                      tot++;
                      ans.add(i);
                  }
                  for(int j=0;((j<=tot)&&(i*ans.get(j)<n));j++)
                  {
                      valid[i*ans.get(j)]=false;
                      if(i%ans.get(j)==0)
                          break;
                  }
              }
          }
      }
      
    • 质因数分解

      static void factor(int n,ArrayList<Integer>ans, ArrayList<Integer>exp)
      {
      	int tmp=(int)((double)Math.sqrt(n)+1);
          int tot=0;
          int now=n;
          for(int i=2;i<=tmp;i++)
      	{
              if(now%i==0)
              {
                  ans.add(i);
                  exp.add(0);
                  while(now%i==0)
                  {
                      int oldValue=exp.get(tot);
                      exp.set(tot,oldValue+1);
                      now/=i;
                  }
                  tot++;
              }
          }
          if(now!=1)
      	{
              ans.add(now);
              exp.add(1);
              tot++;
          }
      }
      

不定方程

  • 基本概念
    • 不定方程定义:
      • 变量个数多于方程个数,并且只考虑整数解的方程被称之为不定方程。
      • 典型的二元一次不定方程形式为 a x + b y = c ax+by=c ax+by=c,其中 a 、 b 、 c a、b、c abc皆为已知整数, a 、 b a、b ab都不为 0, x 、 y x、y xy​为未知数。
  • 性质
    • 二元一次不定方程 a x + b y = c ax+by=c ax+by=c 有解的充要条件是 ( a , b ) ∣ c (a,b)|c (a,b)c
      • ( a , b ) ∣ c (a,b)|c (a,b)c 的时候该方程等价于 a ( a , b ) x + b ( a , b ) y = c ( a , b ) \frac{a}{(a,b)}x+\frac{b}{(a,b)}y=\frac{c}{(a,b)} (a,b)ax+(a,b)by=(a,b)c
      • 由最大公约数的性质知道存在 x 0 ′ , y 0 ′ x_0',y_0' x0,y0,使得 a x 0 ′ + b y 0 ′ = ( a , b ) ax_0'+by_0'=(a,b) ax0+by0=(a,b)。此时 x 0 = x 0 ′ × c ( a , b ) x^0=x_0'\times \frac{c}{(a,b)} x0=x0×(a,b)c y 0 = y 0 ′ × c ( a , b ) y^0=y_0'\times \frac{c}{(a,b)} y0=y0×(a,b)c​为原不定方程的一组解。
    • 假设二元一次不定方程 a x + b y = c ax+by=c ax+by=c 有解,并且 x 0 、 y 0 x_0、y_0 x0y0 为方程的一组解,则它的所有解可以表示为 x = x 0 − b ( a , b ) t x=x_0-\frac{b}{(a,b)}t x=x0(a,b)bt y = y 0 + a ( a , b ) t y=y_0+\frac{a}{(a,b)}t y=y0+(a,b)at,其中 t t t​ 为任意整数。
    • 要求二元一次不定方程 a x + b y = c ax+by=c ax+by=c 的解为非负整数,假设 ( a , b ) = 1 (a,b)=1 (a,b)=1
      • c > a b − a − b c>ab-a-b c>abab时,则方程一定有非负解,解的个数等于$\Big [ \frac{c}{ab} \Big ] $或 [ c a b ] − 1 \Big [ \frac{c}{ab} \Big ] -1 [abc]1
      • c = a b − a − b c = ab-a-b c=abab时,方程一定没有非负解。
        • 其中式子中的 [ c a b ] \Big [ \frac{c}{ab} \Big ] [abc]表示的是不超过实数 c a b \frac{c}{ab} abc的最大整数。

同余方程和欧拉定理

  • 基本概念

    • 假设 m ≠ 0 m≠0 m=0 。若 m ∣ a − b m|a-b mab 则称 a a a 同余于 b b b m m m ,记作 a ≡ b ( m o d m ) a\equiv b(\mathrm{mod} m) ab(modm)

    • m ≥ 1 , ( a , m ) = 1 m≥1,(a,m)=1 m1,(a,m)=1,则存在 c c c 使得 c a ≡ 1 ( m o d m ) ca\equiv1(\mathrm{mod}m) ca1(modm)

      • c c c 被称为 a a a 对模 m m m 的逆,记作 a − 1 a^{-1} a1
    • 设整系数多项式 f ( x ) = a n x n + … + a 1 x + a 0 f(x)=a_nx^n+…+a_1x+a_0 f(x)=anxn++a1x+a0

      • 方程 f ( x ) ≡ 0 ( m o d m ) f(x)\equiv 0(\mathrm{mod} m) f(x)0(modm) 被称之为模 m m m 的同余方程。
      • 假设 x = x 0 x=x_0 x=x0 是方程的一个解,则由同余的性质知 x 0 + k m x_0+km x0+km 皆为方程的解。
        • 当说模m的同余方程的两个不同的解的时候,往往指的是在模意义下的不同,即两者模m不同余。
    • n n n 是正整数, φ ( n ) φ(n) φ(n) 是1,2,…,n中和n互质的数的个数,可以证明
      ϕ ( n ) = n ∏ p ∣ n ( 1 − 1 p ) \Large{\phi(n)=n \prod_{p|n} (1-\frac{1}{p})} ϕ(n)=npn(1p1)

      • φ ( n ) φ(n) φ(n)又被称为欧拉函数。
  • 性质

    • 可以用扩展 Euclid 算法求解 a a a 对模 m m m 的逆。

      • 因为 ( a , m ) = 1 (a,m)=1 (a,m)=1,所以可以通过扩展 Euclid 算法求得 x , y x,y x,y 使得 a x + m y = 1 ax+my=1 ax+my=1
      • 易证 a x ≡ 1 ( m o d m ) ax \equiv1(\mathrm{mod} m) ax1(modm)
    • a ≡ a ′ ( m o d m ) a \equiv a'(\mathrm{mod} m) aa(modm) b ≡ b ′ ( m o d m ) b \equiv b'(\mathrm{mod} m) bb(modm),则有 a + b ≡ a ′ + b ′ ( m o d m ) a+b \equiv a'+b'(\mathrm{mod} m) a+ba+b(modm) a b ≡ a ′ b ′ ( m o d m ) ab \equiv a'b'(\mathrm{mod} m) abab(modm)

      • d d d 为非负整数, a d ≡ a ′ d ( m o d m ) a^d \equiv a'^{d}(\mathrm{mod} m) adad(modm)
      • a a a 对模 m m m 的逆存在,则 a ′ a' a 对模 m m m 的逆也存在,并且 a − 1 ≡ a ′ − 1 ( m o d m ) a^{-1} \equiv a'^{-1}(\mathrm{mod} m) a1a1(modm)
    • 欧拉定理(Euler定理)。

      • ( a , m ) = 1 (a,m)=1 (a,m)=1,则 a ϕ ( m ) ≡ 1 ( m o d m ) a^{\phi(m)}\equiv1(\mathrm{mod} m) aϕ(m)1(modm)
    • 费马小定理(Fermat 小定理)。

      • 对任意 a a a 和任意质数 p p p 有, a p ≡ a ( m o d p ) a^p\equiv a(\mathrm{mod}p) apa(modp)
      • p ∤ a p\not{|}a pa 时,进一步有 a p − 1 ≡ a ( m o d p ) a^{p-1}\equiv a(\mathrm{mod}p) ap1a(modp)
    • m m m 的一次同余方程F 可以通过扩展 Euclid 算法进行求解。

      • 方程有解的充要条件为 ( a , m ) ∣ b (a,m)|b (a,m)b 。在有解的时候,它的模 m m m 意义下不同的解的个数为 ( a , m ) (a,m) (a,m)

      • 假设 x = x 0 x=x_0 x=x0 a x ≡ b ( m o d m ) ax\equiv b(\mathrm{mod}m) axb(modm)方程的一个解,那么所有模m意义下不同的解可以表示成
        x ≡ x 0 + m ( a , m ) t ( m o d m ) \Large{x\equiv x_0+\frac{m}{(a,m)}t(\mathrm{mod} m)} xx0+(a,m)mt(modm)
        其中 t = 0 , 1 , 2 , … , ( a , m ) − 1 t=0,1,2,…,(a,m)-1 t=0,1,2,,(a,m)1

      • 特解 x 0 x_0 x0 的求法是先通过扩展 Euclid 算法求得 x 0 ′ x_0' x0 使得 a x 0 ′ ≡ ( a , m ) ( m o d m ) ax_0'\equiv (a,m)(\mathrm{mod}m) ax0(a,m)(modm),然后只需要让 x 0 = x 0 ′ × b ( a , m ) x_0 =x_0' \times \frac{b}{(a,m)} x0=x0×(a,m)b

    • 孙子定理或中国剩余定理

      • m 1 , … , m k m_1,…,m_k m1,,mk 是两两互质的正整数。

        • 对于任意整数 a 1 , … , a k a_1,…,a_k a1,,ak 来说,一次同余方程组
          { x ≡ a 1 ( m o d m 1 ) ⋯ x ≡ a k ( m o d m k ) \Large{\left\{\begin{matrix} x\equiv a_1(\mathrm{mod}m_1)\\ \cdots\\ x\equiv a_k(\mathrm{mod}m_k) \end{matrix}\right.} xa1(modm1)xak(modmk)
          1 ≤ i ≤ k 1≤i≤k 1ik必有解。
      • 解答

        • 定义
          m = ∏ 1 k m i M i = m m i \Large{ m=\prod_{1}^{k}m_i\quad M_i=\frac{m}{m_i}} m=1kmiMi=mim

        • 由于 m i m_i mi M i M_i Mi 互质,所以存在 M i M_i Mi 对于模 m i m_i mi 的逆 M i − 1 M_i^{-1} Mi1

        • 方程组在模m意义下的唯一解可以表示为
          x = ∑ 1 k M i ⋅ M i − 1 ⋅ a i ( m o d m ) \Large{x=\sum_{1}^{k}M_i·M_i^{-1}·a_i(\mathrm{mod} m)} x=1kMiMi1ai(modm)

    • 对于更加一般的一次同余方程组,可以转化为孙子定理的标准形式求解

  • 代码实现

    • 单变元模线性方程

      ArrayList<Integer> line_mod_equation(int a,int b,int n)
      {
          ArrayList<Integer> result = new ArrayList<>();
          Int x=new Int();
          Int y=new Int();
          int d=Euclid.extend_gcd(a,n,x,y);
          
          if(b%d==0)
          {
              x.value%=n;
              x.value+=n;
              x.value%=n;
              result.add(x.value*(b/d)%(n/d));
              for(int i=1;i<d;i++)
                  result.add((result.get(0)+i*n/d)&n);
          }
          return result;
      }
      
    • 中国剩余定理

      int solveCRT(int[] a,int[] m,int n)
      {
          int M=1;
          for(int i=0;i<n;i++)
              M*=m[i];
      	int result=0;
      	for(int i=0;i<n;i++)
          {
              Int x=new Int();
              Int y=new Int();
              int tmp=M/m[i];
              int d=Euclid.extend_gcd(tmp,m[i],x,y);
              result=(result+tmp*x.value*a[i])%M;
          }
          return (result+M)%M;
      }
      
    • 求欧拉函数

      public class Euler 
      {
          int limit;
          int[] minDiv,phi,sum;
          
          Euler(int limit)
          {
              this.limit=limit;
              minDiv=new int[limit];
              phi=new int[limit];
              sum=new int[limit];
          }
          void getPhi()
          {
              //素数筛
              for(int i=1;i<limit;i++)
                  minDiv[i]=i;
              for(int i=2;i*i<limit;i++)
              {
                  if(minDiv[i]==i)
                  {
                      for(int j=i*i;j<limit;j+=i)
                          minDiv[j]=i;
                  }
              }
              //计算欧拉函数值
              phi[1]=1;
              for(int i=2;i<limit;i++)
              {
                  phi[i]=phi[i/minDiv[i]];
                  if((i/minDiv[i])%minDiv[i]==0)
                      phi[i]*=minDiv[i];
                  else
                      phi[i]=minDiv[i]-1;
              }
          }
      }
      

原根、离散对数和二项同余方程

  • 基本概念

    • 原根

      • m m m 为正整数, ( a , m ) = 1 (a, m)=1 (a,m)=1,若 d d d 是最小的使得 a d ≡ 1 (   m o d   m ) a^{d} \equiv 1(\bmod m) ad1(modm) 成立的正整数, 则 d d d 被称为 $ a $ 对模 $ m $ 的指数, 记作 δ m ( a ) \delta_{m}(a) δm(a)

      • δ m ( a ) = φ ( m ) \delta_{m}(a)=\varphi(m) δm(a)=φ(m),则称 a a a 是模 m m m 的原根。其中 φ \varphi φ​ 为欧拉函数。
        a ϕ ( m ) ≡ 1 (   m o d   m ) \Large a^{\phi(m)}\equiv 1(\bmod m) aϕ(m)1(modm)

    • 设模 m m m 有原根 g g g

      • 对任意满足 ( a , m ) = 1 (a, m)=1 (a,m)=1 a a a,必存在唯一 γ \gamma γ,使得 g γ ≡ a (   m o d   m ) g^{\gamma} \equiv a(\bmod m) gγa(modm) 0 ⩽ γ < φ ( m ) 0 \leqslant \gamma<\varphi(m) 0γ<φ(m)
      • γ \gamma γ a a a 对模 m m m 的以 g g g 为底的指标, 记作 γ m , g ( a ) \gamma_{\mathrm{m}, \mathrm{g}}(a) γm,g(a),在不产生混淆的情况下, 可简写作 γ m ( a ) \gamma_{m}(a) γm(a) γ ( a ) \gamma(a) γ(a)
    • n ⩾ 2 n \geqslant 2 n2 。同余方程 x n ≡ a (   m o d   m ) x^{n} \equiv a(\bmod m) xna(modm) 被称为是模 m m m 的二项同余方程。

  • 性质

    • ( a , m ) = 1 (a, m)=1 (a,m)=1 a d ≡ 1 (   m o d   m ) a^{d} \equiv 1(\bmod m) ad1(modm),则必有 $\delta_{m}(a) \mid d $ 。
    • 由 Euler 定理和性质 1 知, δ m ( a ) ∣ φ ( m ) \delta_{m}(a) \mid \varphi(m) δm(a)φ(m)
    • a 0 , a 1 , ⋯   , a δ m ( a ) − 1 a^{0}, a^{1}, \cdots, a^{\delta_{m}(a)-1} a0,a1,,aδm(a)1 δ m ( a ) \delta_{m}(a) δm(a) 个数模 m m m 互不同余。
    • 模 $ m $ 有原根的充要条件是 m = 1 , 2 , 4 , p α , 2 p α m=1,2,4, p^{\alpha}, 2 p^{\alpha} m=1,2,4,pα,2pα,其中 p p p 是奇素数, α \alpha α 是正整数。
    • γ m ( a b ) ≡ γ m ( a ) + γ m ( b ) (   m o d   φ ( m ) ) \gamma_{m}(a b) \equiv \gamma_{m}(a)+\gamma_{m}(b)(\bmod \varphi(m)) γm(ab)γm(a)+γm(b)(modφ(m))
    • γ m ( a k ) ≡ k × γ m ( a ) (   m o d   φ ( m ) ) \gamma_{m}\left(a^{k}\right) \equiv k \times \gamma_{m}(a)(\bmod \varphi(m)) γm(ak)k×γm(a)(modφ(m))
  • 常用算法

    • m m m 的原根的计算
      • 通过随机一个数 g g g​ 然后验证其是否为原根;
      • 计算最小正原根
    • 离散对数问题
      • 问题描述:已知模 m m m 和它的原根 g g g,若 $ (a, m)=1 $,求 $ \gamma_{\mathrm{m}, \mathrm{g}}(a)$​ 。
      • 用空间换时间的算法:
        • 简写 γ m , g ( a ) \gamma_{\mathrm{m}, \mathrm{g}}(a) γm,g(a) γ \gamma γ 。那么 g γ ≡ a (   m o d   m ) g^{\gamma} \equiv a(\bmod m) gγa(modm) 。令 q = [ φ ( m ) ] q=[\sqrt{\varphi(m)}] q=[φ(m) ],把 $ \gamma $ 写作 i q + j iq+j iq+j 的形式,使得 0 ⩽ j < q 0 \leqslant j0j<q 。因为 γ < φ ( m ) \gamma<\varphi(m) γ<φ(m),所以 i = O ( φ ( m ) ) i=O(\sqrt{\varphi(m)}) i=O(φ(m) )
        • g i q + j ≡ a (   m o d   m ) g^{i q+j} \equiv a(\bmod m) giq+ja(modm)推出 a ( g − q ) i ≡ g j (   m o d   m ) a\left(g^{-q}\right)^{i} \equiv g^{j}(\bmod m) a(gq)igj(modm)。注意由于 g g g m m m 的原根,所以 g g g 对于模 m m m 的逆必存在。
        • 预先把 g j g^{j} gj q q q 种可能的数值都计算出来,放入哈希表中。然后从 0 0 0 开始尝试 i i i 的数值,再去哈希表中查找 a ( g − q ) i a\left(g^{-q}\right)^{i} a(gq)i 。若能找到, 则根据对应的 i i i j j j 算出 $ \gamma $ 。
    • 求解特殊二项同余方程。
      • 问题描述:假设模是质数 p p p,且 p ∤ a p\not{\mid}a pa n ≥ 2 n≥2 n2,求解模 p p p 的二项同余方程 x n = a (   m o d   p ) x^n=a(\bmod p) xn=a(modp)
      • 解法
        • 首先计算出 p p p 的原根 g g g 。然后方程两边一起做指标运算变成 n γ ( x ) = γ ( a ) (   m o d   p − 1 ) n\gamma (x)=γ(a)(\bmod p-1) (x)=γ(a)(modp1)
        • γ ( a ) γ(a) γ(a) 可以通过解离散对数的算法计算出来。
        • 如此一来,方程就变成了一个简单的一次同余方程。根据解一次同余方程的算法解出 γ ( x ) γ(x) γ(x) 的所有解,再利用 x = g γ ( x ) (   m o d   p ) x=g^{\gamma(x)}(\bmod p) x=gγ(x)(modp) 算出 x x x​ 的所有解。
  • 代码实现

    • 求原根

      public class primitiveRoot 
      {
          ArrayList<Integer> arr;
          
          primitiveRoot()
          {
              arr=new ArrayList<>();
          }
      	//计算快速幂
          int quick_pow_mod(int a,int x,int mod)
          {
              if(x==0)
                  return 1%mod;
              int tmp=quick_pow_mod(a,x>>1,mod);
              tmp=tmp*tmp%mod;
              if(x%2==1)
                  tmp=tmp*a%mod;
              return tmp;
          }
      	//测试
          boolean g_test(int g,int p)
          {
              for(int i=0;i<arr.size();i++)
              {
                  int q = arr.get(i);
                  if(quick_pow_mod(g,(p-1)/q,p)==1)
                      return false;
              }
              return true;
          }
      	//计算
          int getPrimitiveRoot(int p)
          {
              //质因数分解
              int tmp=p-1;
              for(int i=2;i*i<=tmp;i++)
              {
                  if(tmp%i==0)
                  {
                      arr.add(i);
                      while(tmp%i==0)
                      {
                          tmp/=i;
                      }
                  }
              }
              if(tmp!=1)
                  arr.add(tmp);
              int g=2;
              while(true)
              {
                  if(g_test(g, p))
                      return g;
                  if(g>p)
                      return -1;
                  g++;
              }
          }
      }
      
    • 离散对数

      static int getDiscreteLog(int x,int n,int m)
      {
      	int[] arr = new int[(int)Math.sqrt(m) + 1];
      	int s = (int) Math.ceil(Math.sqrt(m));
          int cur=1;
          for(int i=0;i<s;i++)
          {
              arr[i] = cur;
              cur = (int) ((long)cur * x % m);
          }
          // x 的逆元 (模 m) 的s次幂
          int tmp=quickPowMod.quick_pow_mod(x, m - 2, m);
      	int curInv = quickPowMod.quick_pow_mod(tmp, s, m);
      	int y = n;
          for (int i = 0; i < s; i++) 
      	{
              for (int j = 0; j < s; j++)
              {
                  if (arr[j] == y)
                  {
                      return i * s + j;
                  }
              }
              y = (int) ((long)y * curInv % m);
          }
          return -1;
      }
      
    • n次剩余

      static ArrayList<Integer> residue(int p,int N,int a)
      {
          //求 p 的原根 g
          primitiveRoot pRoot=new primitiveRoot();
          int g=pRoot.getPrimitiveRoot(p);
          //求离散对数m
          int m= discreteLog.getDiscreteLog(g,a,p);
          //存储结果
          ArrayList<Integer> result=new ArrayList<>();
          if(a==0)
          {
              result.add(0);
              return result;
          }
          if(m==-1)
              return result;
      
          // 构造线性同余方程 Ax = C (mod B),其中 A = N, B = p-1, C = m
          int A=N,B=p-1,C=m;
          Int x=new Int();
          Int y=new Int();
              
          //计算 gcd结果
          int d=Euclid.extend_gcd(A,B,x,y);
          if(C%d!=0)
              return result;
          
          // 将 x 的值更新为线性同余方程 Ax = C (mod B) 的一个解
          x.value=x.value*(C/d)%B;
          int delta=B/d;
          for(int i=0;i<d;i++)
          {
              // 将解转换为对应的元素(使用原根 g 和模幂运算) 
              x.value=((x.value+delta)%B+B)%B;
              result.add(quickPowMod.quick_pow_mod(g, x.value, p));
          }
          Collections.sort(result);
          return result;
      }
      

连分数

  • 基本概念

    • 分数式

      a 0 + 1 a 1 + 1 a 2 + 1 a 3 + 1 … a n \Large{a_{0}+\cfrac{1}{a_{1}+\cfrac{1}{{a_{2}} +\cfrac{1}{a_{3} +\cfrac{1}{\dots a_{n} }}}}} a0+a1+a2+a3+an1111

      • 被称为有限连分数,其中 a 0 a_0 a0 是整数,其他所有的 a i a_i ai 都是正整数。简写记作 [ a 0 ; a 1 , a 2 , … , a n ] [a_0;a_1,a_2,…,a_n] [a0;a1,a2,,an]。在 0 ≤ k ≤ n 0≤k≤n 0kn 时, [ a 0 ; a 1 , a 2 , … , a k ] [a_0;a_1,a_2,…,a_k] [a0;a1,a2,,ak] 被称为对应有限连分数的第 k k k 个渐进分数。
    • 分数式

      a 0 + 1 a 1 + 1 a 2 + 1 a 3 … \Large{a_{0}+\cfrac{1}{a_{1}+\cfrac{1}{{a_{2}} +\cfrac{1}{a_{3} \dots}}}} a0+a1+a2+a3111

      • 被称为无限连分数,其中 a 0 a_0 a0 是整数,其他所有的 a i a_i ai 都是正整数。简写记作 [ a 0 ; a 1 , a 2 , … ] [a_0;a_1,a_2,…] [a0;a1,a2,]。对于任意非负整数 k k k [ a 0 ; a 1 , a 2 , … , a k ] [a_0;a_1,a_2,…,a_k] [a0;a1,a2,,ak] 被称作对应无限连分数的第 k k k 个渐进分数。
      • 对于无限连分数 [ a 0 ; a 1 , a 2 , … ] [a_0;a_1,a_2,…] [a0;a1,a2,],若存在极限 lim ⁡ k → ∞ [ a 0 ; a 1 , a 2 , … , a k ] = θ \lim_{k \to \infty}[a_0;a_1,a_2,…,a_k]=\theta limk[a0;a1,a2,,ak]=θ,就说该无限连分数是收敛的, θ \theta θ被称为它的值。
    • 一个有理分数 p / q p/q p/q 被称之为实数 x x x 的最佳有理逼近,当且仅当在所有分母不超过 q q q 的有理分数中, ∣ p q − x ∣ |\frac{p}{q}-x| qpx最小

  • 性质

    • 有限连分数的值是一个有理分数。

    • 任意有理分数有且仅有两种有限连分数表示式。

      • 第一种为 [ a 0 ; a 1 , a 2 , … , a n ] [a_0;a_1,a_2,…,a_n] [a0;a1,a2,,an],其中 a n > 1 a_n>1 an>1;
      • 第二种可以表示成 [ a 0 ; a 1 , a 2 , … , a n − 1 , 1 ] [a_0;a_1,a_2,…,a_n-1,1] [a0;a1,a2,,an1,1]​。
    • 任意有理分数 p / q p/q p/q 其中 ( p , q ) = 1 (p,q)=1 (p,q)=1,它的有限连分数表示式可以通过辗转相除法得到。

    • 比较有限连分数的大小。

      • a = [ a 0 ; a 1 , a 2 , … , a n ] a=[a_0;a_1,a_2,…,a_n] a=[a0;a1,a2,,an] b = [ b 0 ; b 1 , b 2 , … , b s ] b=[b_0;b_1,b_2,…,b_s] b=[b0;b1,b2,,bs] 为两个有限连分数。

      • 大小比较

        • a = b a=b a=b 当且仅当 n = s n=s n=s a i = b i a_i=b_i ai=bi,其中 0 ≤ i ≤ n 0≤i≤n 0in
        • a ≠ b a≠b a=b,分两种情况讨论。
          • 若存在 k k k 使得 k k k 是满足 a k ≠ b k a_k≠b_k ak=bk的最小的非负整数,则 a < b aa<b 当且仅当 ( − 1 ) k ( a k − b k ) < 0 (-1)^k(a_k-b_k)<0 (1)k(akbk)<0
          • 若不存在这样的 k k k,则必有其中一个连分数的序列是另一个的前缀,不妨假设 a a a b b b 的前缀,即 n < s nn<s a i = b i a_i=b_i ai=bi,其中 0 ≤ i ≤ n 0≤i≤n 0in,则 a < b aa<b 当且仅当 n n n​ 是偶数。
      • a ( k ) a^{(k)} a(k) 表示连分数 a a a 的第 $ k$​ 个渐进分数
        a ( 1 ) > a ( 3 ) > a ( 5 ) > ⋯ > a ( 2 s − 1 ) > ⋯ a ( 0 ) < a ( 2 ) < a ( 4 ) < ⋯ < a ( 2 t ) < ⋯ a ( 2 s − 1 ) > a ( 2 t ) s ≥ 1 , t ≥ 0 \Large{a^{(1)}>a^{(3)}>a^{(5)}>\cdots>a^{(2s-1)}>\cdots}\\ \Large{a^{(0)}a^{(2t)} \qquad s\ge1,t\ge 0} a(1)>a(3)>a(5)>>a(2s1)>a(0)<a(2)<a(4)<<a(2t)<a(2s1)>a(2t)s1,t0

    • 无限连分数一定收敛,且值为无理数。

      • 任何无理数都存在唯一的一个无限连分数表示。
    • 比较无限连分数的大小

      • a = [ a 0 ; a 1 , a 2 , … ] a=[a_0;a_1,a_2,…] a=[a0;a1,a2,] b = [ b 0 ; b 1 , b 2 , … ] b=[b_0;b_1,b_2,…] b=[b0;b1,b2,] 为两个无限连分数。
      • 大小比较
        • a = b a=b a=b 当且仅当 a i = b i a_i=b_i ai=bi,其中 i ≥ 0 i \ge 0 i0
        • a ≠ b a≠b a=b,则存在最小的非负整数 k k k,满足 a k ≠ b k a_k≠b_k ak=bk,那么 a < b aa<b 当且仅当 ( − 1 ) k ( a k − b k ) < 0 (-1)^k(a_k-b_k)<0 (1)k(akbk)<0​。
    • 实数 x x x 的连分数表示的所有渐进分数都是 x x x​ 的最佳有理逼近。

      • 实数 x x x 的所有最佳有理逼近,都可以表示成 [ a 0 ; a 1 , a 2 , … , a n − 1 , a n ′ ] [a_0;a_1,a_2,…,a_{n-1},a_n'] [a0;a1,a2,,an1,an]。其中 a n 2 ≤ a n ′ ≤ a n \frac{a_n}{2}≤a_n'≤a_n 2ananan,并且 [ a 0 ; a 1 , a − 2 , … , a n − 1 , a n ] [a_0;a_1,a-2,…,a_{n-1},a_n] [a0;a1,a2,,an1,an] x x x 的第 n n n个渐进分数。所以任意实数的所有最佳有理逼近与它的所有渐进分数一一对应。

你可能感兴趣的:(算法学习,算法,线性代数)