【数论】Miller_Rabin、线性求逆元

本文介绍了一种高效的素数检测算法——Miller-Rabin算法,并详细解析了其背后的数学原理。同时,文章还阐述了一种快速计算逆元的方法,适用于线性求逆元场景。通过具体实例和代码实现,读者可以深入了解这些算法的工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

typedef long long LL;

Miller_Rabin素数测试

二次探测定理

如果ppp是素数,xxx是小于ppp的正整数,且x2≡1(modp)x^2\equiv1\pmod px21(modp),那么要么x=1x=1x=1,要么x=p−1x=p-1x=p1
解读: 因为x2mod  p=1x^2\mod p=1x2modp=1,即p∣x2−1p|x^2-1px21,也即p∣(x+1)(x−1)p|(x+1)(x-1)p(x+1)(x1)
由于ppp是素数且x<px<px<p,那么只可能是x−1x-1x1能被ppp整除(此时x=1x=1x=1)或x+1x+1x+1能被ppp整除(此时x=p−1x=p-1x=p1)。

要测试整数nnn是否为素数,若nnn是素数,根据费马定理,有an−1mod  n=1a^{n-1}\mod n=1an1modn=1
首先任选一个数做底数aaa
我们令n−1=d⋅2Rn-1=d\cdot 2^Rn1=d2R,其中ddd是一个奇数,于是an−1mod  n=(ad)2Rmod  n=ad⋅2R−1⋅ad⋅2R−1mod  na^{n-1}\mod n=(a^d)^{2^R}\mod n=a^{d\cdot 2^{R-1}}\cdot a^{d\cdot 2^{R-1}}\mod nan1modn=(ad)2Rmodn=ad2R1ad2R1modn
根据二次探测定理, ad⋅2R−1mod  na^{d\cdot 2^{R-1}}\mod nad2R1modn要么等于111要么等于n−1n-1n1
如果ad⋅2R−1mod  na^{d\cdot 2^{R-1}}\mod nad2R1modn既不等于111也不等于n−1n-1n1nnn一定不是素数,结束讨论。
如果ad⋅2R−1mod  n=n−1a^{d\cdot 2^{R-1}}\mod n=n-1ad2R1modn=n1,我们认为nnn是素数,结束讨论。
如果ad⋅2R−1mod  n=1a^{d\cdot 2^{R-1}}\mod n=1ad2R1modn=1,继续讨论:

  • 根据二次探测定理, ad⋅2R−2mod  na^{d\cdot 2^{R-2}}\mod nad2R2modn要么等于111要么等于n−1n-1n1。……

上述讨论过程中,如果存在某个整数kkk,使得ad⋅2kmod  n=n−1(0⩽k<R)a^{d\cdot 2^k}\mod n = n-1 (0\leqslant k<R)ad2kmodn=n1(0k<R),我们就认为nnn是素数,结束讨论。
或者,若admod  n=1a^d\mod n=1admodn=1nnn是素数。

这是一种不确定算法,每一次测试的准确率约为75%75\%75%
若进行了mmm次测试,时间复杂度为O(mlog⁡3n)O(m\log_3n)O(mlog3n)

bool miller_rabin(LL n){
  if(n==2)return 1;
  if(n<2||!(n%2))return 0;
  LL d=n-1;int r=0;
  while(!(d&1))d/=2,r++;
  for(int i=1;i<=10;i++){
    LL a=rand()%(n-2)+2,x=Pow(a,d,n);
    for(int j=1;j<=r;j++){
      LL y=Mul(x,x,n);
      if(y==1&&x!=1&&x!=n-1)return 0;
      x=y;
    }
    if(x!=1)return 0;
  }
  return 1;
}

一些玄学操作:

  • n<4759123141n<4759123141n<4759123141时,只需检测a=2,7,61a=2,7,61a=2,7,61,即可确保正确。
  • n<2152302898747n<2152302898747n<2152302898747时,只需检测a=2,3,5,7,11a=2,3,5,7,11a=2,3,5,7,11,即可确保正确。
  • n<341550071728320n<341550071728320n<341550071728320时,只需检测a=2,3,5,7,11,13,17a=2,3,5,7,11,13,17a=2,3,5,7,11,13,17,即可确保正确。

线性求逆元

a−1={1a=1(p−⌊pa⌋)(pmod  a)−1mod  pa>1a^{-1}=\begin{cases} 1&a=1\\ (p-\lfloor\frac pa\rfloor)(p\mod a)^{-1}\mod p&a>1 \end{cases}a1={1(pap)(pmoda)1modpa=1a>1

证明:
显然111的逆元为111
a>1a>1a>1时,已知a⋅a−1≡1(modp)a\cdot a^{-1}\equiv 1\pmod paa11(modp),其中1<a<p1<a<p1<a<p
k=⌊pa⌋,r=pmod  ak=\lfloor\frac pa\rfloor,r=p\mod ak=ap,r=pmoda,那么p=ka+r,0<r<ap=ka+r,0<r<ap=ka+r,0<r<a
则有ka+r≡0(modp)ka+r\equiv 0\pmod pka+r0(modp)
两边同时乘以a−1r−1a^{-1}r^{-1}a1r1得到(ka+r)a−1r−1≡0(modp)(ka+r)a^{-1}r^{-1}\equiv 0\pmod p(ka+r)a1r10(modp)
k⋅r−1+a−1≡0(modp)k\cdot r^{-1}+a^{-1}\equiv 0\pmod pkr1+a10(modp)
转换得
a−1=−k⋅r−1mod  p=−⌊pa⌋(pmod  a)−1mod  p=(p−⌊pa⌋)(pmod  a)−1mod  p\begin{aligned} a^{-1}&=-k\cdot r^{-1}\mod p\\ &=-\lfloor\frac pa\rfloor(p\mod a)^{-1}\mod p\\ &=(p-\lfloor\frac pa\rfloor)(p\mod a)^{-1}\mod p \end{aligned}a1=kr1modp=ap(pmoda)1modp=(pap)(pmoda)1modp

时间复杂度:O(n)O(n)O(n)

void make_inv(int*inv,int n,int p){
  inv[1]=1;
  for(int i=2;i<=n;i++)inv[i]=(p-p/i)*inv[p%i]%p;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值