zoukankan      html  css  js  c++  java
  • miller_rabin与pollard_rho与快速乘法

    板子

     1 #include <bits/stdc++.h>
     2 #define LL long long
     3 using namespace std;
     4 LL n; vector <LL> z;
     5 const LL mo=1e9+7;
     6 LL gcd(LL x,LL y){
     7     return y?gcd(y,x%y):abs(x);
     8 }
     9 LL po(LL x,LL y){
    10     LL z=1; x%=mo;
    11     for (;y;y>>=1,x=x*x%mo)
    12     if (y&1) z=z*x%mo;
    13     return z;
    14 }
    15 LL XX(LL x,LL y,LL z){
    16 /*
    17     (long double)x/z*y求商可以有微小的误差,之后反正会+z%z模回来
    18     但如果 没有x%=z,y%=z,商的误差可能会很大,这样作差时会±k*maxLL 而GG
    19 */
    20     x%=z,y%=z; return ((x*y-(LL)((long double)x/z*y)*z)%z+z)%z;
    21     // return (__int128)x*y%z;
    22 }
    23 int St(LL a,LL b){        //a^(b-1)!=1?&&二次探测
    24     //二次探测定理:如果p是奇素数,则x^2≡1(mod p)的解为x=1||x=p-1(mod p);  
    25     if (a==b) return 0;
    26     LL ans1=1,ans=1;
    27     for (int i=64;i>=0;i--){
    28         ans=XX(ans1,ans1,b);
    29         if (ans==1&&ans1!=1&&ans1!=b-1) return 1;
    30         if ((b-1)&(1LL<<i)) ans=XX(ans,a,b);
    31         ans1=ans;
    32     }
    33     return ans!=1;
    34 }
    35 int isP(LL x){        // x=1时为0;
    36     return !(St(2,x)||St(3,x)||St(5,x)||St(7,x)||St(11,x)||St(13,x)||St(17,x)||St(19,x)||St(23,x));
    37 }
    38 LL ra(LL x){
    39     return (rand()*2147483647LL+rand()*32767LL+rand())%x;
    40 }
    41 LL pro(LL x){
    42     LL x1=ra(x),x2=(XX(x1,x1,x)+1)%x,p=gcd(x1-x2,x);
    43     while (p==1){        //不用判x=y,大不了返回x 
    44         x1=(XX(x1,x1,x)+1)%x;
    45         x2=(XX(x2,x2,x)+1)%x;
    46         x2=(XX(x2,x2,x)+1)%x;
    47         p=gcd(x1-x2,x);
    48     }
    49     return p;
    50 }
    51 void divide(LL x){
    52     while (!(x&1)) z.push_back(2),x/=2;
    53     if (x==1) return;
    54     if (isP(x)) z.push_back(x);else{
    55         LL y=pro(x);
    56         divide(x/y); divide(y);
    57     }
    58 }
    59 int main(){
    60     scanf("%lld",&n);
    61     divide(n);
    62     printf("%lld=",n);
    63     if (n==1){
    64         puts("1"); return 0;
    65     }
    66     sort(z.begin(),z.end());
    67     for (int q=0,h=0;q<z.size();q=h){
    68         while (h<z.size()&&z[h]==z[q]) ++h;
    69         if (q!=h-1) printf("%lld^%d",z[q],h-q); else printf("%lld",z[q]);
    70         if (h!=z.size()) printf("*");
    71     }
    72     puts("");
    73 }
    冰菓

    (没想到会在大学概统课写小论文时,回来补充高中的博客。。)

    面对密码学中的大数问题,如大素数检验,大合数分解,精确的算法在现实的机器下难以实现,所以有了概率算法。

    首先讲大素数检验

    现有的概率检验算法,基本逻辑框架是,对于一个正奇数n,令集合S={1,…,n-1},存在一个S的子集W,W满足两个性质:

    1. 当给出一个a∈S ,能在较快的时间(多项式时间复杂度)内,判断是否有 a∈W;
    2. 若n为素数,则W=S ;若n为合数,则|W| <= k|S| = k(n-1),  k是确定的常数且k∈(0,1)

    简单理解:若a∈S而a∉W,则能够判定n不是素数。一个合数n,有k的概率不能被检验出来。

    检验的流程:每次独立随机生成 a∈S,对n作上述判定。经过t轮判断后,结束检验。

    此时,合数n依然被误认为是素数的概率<=kt,t足够大时,就几乎不会出错了。

    目标就是构造这样“良好的W”:

    ①很弱的办法——公约数检验(我起的名字)

      $W={a  | gcd(a,n)=1,a in S}$  ,也就是说,随机生成的a必须和n有“非1公约数”,才能判定n不是素数。

      这时候,$|W|=φ(n)$,(φ-欧拉函数),$|W| leq n-sqrt{n}$ ,(考虑$n=p^{2}$,p为质数,这种情况下左式取等号),显然不满足良好W的第二条性质。

    ②尝试改进 ——“费马素性检验”算法

      费马小定理:对于质数$n$,若正整数$a in S$,且$gcd(a,n)=1$,则$a^{n-1}≡1$

      但是,费马小定理只是素数的必要不充分条件,逆命题不成立。

      有一些合数,对于部分a 满足费马小定理,这样的合数被称为“伪素数”(确切的说,是“a的伪素数”),最小的伪素数是341。

      

      假设$W={ a|a in S 且gcd(a,n)=1 且 a^{n-1} ≡ 1 }$

      下面证明一个定理:

      若$W={a_{1},a_{2},...,a_{k}}$,如果$exists a in S 且 gcd(a,n)=1 , a^{n-1} eq 1 ,则 (a cdot a_{i})^{n-1} eq 1$

      则,${a cdot a_{1},a cdot a_{2},...,a cdot a_{k}}$ 也是S的子集, 且与W无交集。

      因此,$|W| leq frac{1}{2} |S|$。

      由上定理知,对于一个n,只要存在$a in S$可以检验出n不是素数,则该检验方法就能满足“良好W”的性质。

      实际上,这种算法确实已经很棒了,优先取2,3,5,7等小质数,可以很快淘汰掉绝大部分合数。

      但是,在伪素数中,还有一类数——卡迈尔数。它对任何$a in S$都满足费马小定理,最小的卡迈尔数是561。

      虽然,1亿以内只有255个卡迈尔数,可一旦遇到了,费马素性检验就退化成了①。

     ③再次改进——Miller_rabin算法

      二次探测定理:  对于质数$n$,若正整数$a in S$,且$a^{2} equiv 1 (mod n)$,则 a=1或-1

     算法原理:

      对于正奇数n,$n-1=r2^{s}$,r为奇数。

      若n为素数,则$a^{r2^{s}} equiv 1$,  则,$a^{r2^{s-1}} = 1或-1$ ;若为1,则,$a^{r2^{s-2}} = 1或-1$ ……

       由此得到,素数n,应满足:$forall a in S,{ a^{r},a^{r2^{1}},a^{r2^{2}},...,a^{r2^{s-1}} }$,要么全为1,要么有一个-1(其后每一项都为1)。

      令W={满足上述条件的a}

      可以证明$|W| leq frac{1}{4} |S|$ ,且不像②那样依赖于n或者a。

       这样,我们就得到了一个“良好的W”,能出色的完成大素数检验的任务了。

    下面补充Miller_rabin一次误判概率$leq frac{1}{4}$的证明,不感兴趣的可以跳过。

     定理1:

       对正整数n,在mod n意义下的m阶有限群${x,x^{2},x^{3},cdots,x^{m}=1}$中,(x为生成元),有$gcd(m,k)$个元素,满足$(x^{i})^{k}=1$。

      证明很简单。若$d=gcd(m,k)$,则满足条件的i的集合$={frac{m}{d},frac{2m}{d},cdots,m}$。

     定理2:

      对于奇素数n,$n-1=h2^{s}$,h为奇数,则对于正奇数t,满足$x^{t2^{r}}=-1$的x的个数$= egin{cases} 0,qquad qquad r geq s \ 2^{r}*gcd(h,t),quad r < s end{cases} $

       证明:

      Case1:$(x^{t2^{r}})^{h}=(x^{h2^{r}})^{t}=ig((x^{h2^{s}})^{2^{r-s}}ig)^{t}=1$,    又$ecause h$为奇数,$ herefore x^{t2^{r}} eq -1$

      Case2:设奇素数n 原根是g, $S={1,g^{1},cdots,g^{n-2}} ,g^{frac{n-1}{2}}=-1$。

      即求,满足$(g^{i})^{t2^{r}}=-1$的i的个数,$i in [0,n-2]$,

      则,$(n-1) mid (it2^{r}-frac{n-1}{2}) qquad Rightarrow qquad (2^{s}h) mid (it2^{r}-h2^{s-1}) $

      设$d=gcd(h,t)$  $Rightarrow (2^{s-r} cdot frac{h}{d}) mid (i cdot frac{t}{d}-2^{s-1-r} cdot frac{h}{d})$

       应取$i=2^{s-1-r} cdot frac{h}{d} cdot (2k+1)$,k为整数,显然,在$i in [0,n-2]$中,分别对应$k in [0,2^{r}d-1]$,一共$2^{r}d$个。

    另外,补充一个有一点点相关的知识:

      素数定理(关于素数个数的定理): π(x)表示不大于x的素数个数, π(x) ~ $frac{x}{ln{x}}$。

      这也说明,从$[1,n]$中随机选一个数,它是素数的概率大约是 $frac {1}{ ln{n}}$

      所以,即使是近50位的十进制大整数,也有约1%的概率是素数。

    ================================================================

    1、a^(b-1)!=1 加上 二次探测  误判率据说是 1/4

    (而这个板子只判了9次  误判概率好像有点高啊)

    2、生日悖论

      期望 sqrt(n)个 [1,n]中随机的数  当中 有两个数是相同的

    3、

     选取xi= (xi-1* xi-1 +1)%n  可以认为是会有循环节的 [1,n]中的随机函数

      根据生日悖论  ,循环节长度期望是 sqrt(n)

     假设 ,p是n的最小质因子, 则p<=sqrt(n)

      同理可得,xi%p的 循环节长度期望是sqrt(p)

     然后,我们用两个指针 i1,i2 分别以一倍速和二倍速扫这些数

      期望sqrt(p)步,i1与i2 在%p意义下是相同的(即在两个循环节的同一个位置,位置的差为一个循环节), 而它们在%n意义下是不同的。

      此时,gcd(i1-i2,n) 是p的倍数,n的约数,于是我们成功分解了一次n,期望用 n^(1/4)次。

      当然 这都是基于期望,也有可能循环节太短找不到,所以要做多次。

    转载请标明出处 http://www.cnblogs.com/cyz666/
  • 相关阅读:
    Educational Codeforces Round 78 (Rated for Div. 2)
    Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)
    Codeforces Round #604 (Div. 2)
    Codeforces Round #603 (Div. 2)
    Educational Codeforces Round 77 (Rated for Div. 2)
    一个逆向的问题
    cppcheck,今天下载了这个软件,准备研究学习一下了
    SQL 显错注入的基本步骤
    OD打印保存执行的汇编指令的脚本
    没事还是不要算卦得好
  • 原文地址:https://www.cnblogs.com/cyz666/p/6369709.html
Copyright © 2011-2022 走看看