zoukankan      html  css  js  c++  java
  • [算法复习] 素数判定:欧拉筛 Miller_Rabin

    摘取了以前的笔记并做了一些补充说明

    9,素数判定

       O(n) + O(1): 线性筛.
        又叫欧拉筛。
        先考虑一种朴素的想法。
        对于每一个数(k), 我们枚举(i),将(ik)标记为合数。
        因为每个数都可以分解成若干个素数的积,我们只需枚举每个素数作为(k)即可。
        但是复杂度依然很高,我们考虑优化。
        对于每个数,仅用它最小的质因数来筛它。
        我们用一个数组存储质数,枚举(i)作为它的倍数,并且每次都判断一下如果(i)是素数,则将其加入素数数组。
        然后我们从小到大枚举(pri[j])用其筛除(i * pri[j]).
        特别的,如果(!(i mod pri[j])) 那么我们筛完就break.
        
        下面我们来证明这个算法的正确性和复杂度。
        
        正确性:
        接下来我们证,如果(!(i mod pri[j])),那么对于后面的(i cdot pri[j+k])来说,用(pri[j+k])来筛一定是不优的,也就是这个剪枝肯定不会导致漏筛。
        因为(!(i mod pri[j]))所以我们可以设(i = t cdot pri[j])
        那么(i cdot pri[j+k] = t cdot pri[j] cdot pri[j+k])
        又知(pri[j+k] > pri[j]),也就是说,用(pri[j+k])来筛,不如等到(i = t cdot pri[j+k])的时候用(pri[j])来筛。
        所以这个剪枝肯定是合法的。
        
        复杂度:
        那么为什么每个数仅被最小的质因数筛除了呢?
        接下来我们证,这个剪枝可以导致每个数仅被最小的质因数筛除.
        (pm[m])(m)的质因数个数,对于一个数(m)(m = prod_{i = 1}^{pm[m]}p_i),其中(p)序列为升序排列,若(m)不是被(p_1)筛除了,我们假设这个数是(p_t)
        我们先考虑(m)质因数大于(2)个的情况:
        那么筛掉(m)时我们枚举到的(i = prod_{i = 1}^{pm[m]}(p_i) / p_t = b cdot p_1),(b)为某个不为(1)正整数。
        此时,(i)会在枚举到(p_1)的时候停下,也就是筛完(b cdot p_1 cdot p_1)就不筛了,也就不会筛(m = b cdot p_1 cdot p_t)了。与假设矛盾。
        再考虑(m)刚好有两个质因数的情况,此时(m = p_1 cdot p_2),那么根据假设,(m)(p_2)筛掉了。
        也就是在(i = p_1)的时候(m)被筛了。
        这显然是不合法的,因为此时(p_2)这个质数还没被加入素数数组。
        所以(m)只可能在(i = p_2)时被(p_1)筛掉。与假设矛盾。
        综上,假设情况是不可能的,(m)必然会被其最小质因数筛除.
        又因为在第二个循环中,每循环一次必筛除一个数,而每个数只会被筛走一次,因此第二个循环的总次数为被筛除的素数个数。所以复杂度是(O(n))
        
        代码:

    void get()
    {
    	z[1] = 1;
    	for(R i = 2; i <= n; i ++)
    	{
    		if(!z[i]) pri[++ tot] = i;
    		//printf("%d
    ", tot);
    		for(R j = 1; j <= tot && 1LL * i * pri[j] <= n; j ++)
    		{
    			z[i * pri[j]] = 1;
    			if(!(i % pri[j])) break;
    		}
    	}
    }
    

      
      O((sqrt{n})): 暴力枚举(sqrt{n})以内的因子
      Miller_Rabin算法:(这部分写的好烂,哪天我重学Miller_Rabin再来更新吧)
        根据费马小定理有(a^{p - 1} equiv 1 (mod quad p)),要求p是质数.
        那么如果对于等式(a^{p - 1} equiv 1 (mod quad p)),枚举多个a,均满足等式,那么可以认为当前的p有很大概率是素数。
        但是依然有很大概率不是,,,因此这个时候采取二次探测来减小错误概率。
        首先有定理:若(a^2 equiv 1 (mod quad p))且p为质数,那么a = 1 或 p - 1.
        证明如下:若等式成立,则(a^{2} - 1 equiv 0 (mod quad p)).
        即((a + 1)(a - 1) equiv 0 (mod quad p)).
        因此要么(a + 1 = p) ---> (a = p - 1).
        或者(a - 1 = 0) ---> (a = 1).
        因为这个探测是在满足费马测试的情况下才进行的,因此对于某个已经被枚举过的a,我们已经有(a^{p - 1} equiv 1 (mod quad p)).我们设当前指数(x = p - 1)
        当p不为2且为素数时,(p)一定为奇数,即(p - 1)一定为偶数.
        因此我们可以把原式看做(a^{frac{x}{2}} cdot a^{frac{x}{2}} equiv 1 (mod quad p)),其中可以设(t = a^{frac{x}{2}})
        那么原式就是(t cdot t equiv 1(mod quad p))
        那么因为这个是直接根据原式化过来的,因此我们已经有它同余1了,因此只需要再判断t是否等于1 或 p - 1即可。
        如果t = 1 且 x为偶数,那么我们就又得到了一个新的式子(a^{frac{x}{2}} equiv 1 (mod quad p))
        此时因为x为偶数,所以我们依然这个把这个新式子当做上面的式子重新做探测,直到不满足t = 1且x为偶数为止。

    本文不允许商业性使用,个人转载请注明出处! 知识共享许可协议
    本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。
  • 相关阅读:
    油猴脚本
    js hook
    js控制台原理检测
    安卓so文件函数动态注册
    js一些简单逆向题目实战
    js基础补充落下的知识点
    js反爬原理
    js容易让人眼瞎的写法
    js基础
    js一些常见非指纹built-in函数
  • 原文地址:https://www.cnblogs.com/ww3113306/p/14647774.html
Copyright © 2011-2022 走看看