• 数论——终结素数判定


    1.基础版(暴力)素数判定:

    bool prime(int n) 
    {
        if (n<=1)
            return false;
        int tmp=sqrt(n);
        for (int i=2;i<=tmp;i++)
            if (n%i==0)
                return false;
        return true;
    }

    2.再诉说一个素数规律。

    //任何一个数都可以写成  6n,6n+1,6n+2,6n+3,6n+4,6n+5这种格式。
    
    //显然6n , 6n+2 , 6n+4   能被2整除  
    //      6n+3               能被3整除     
    //因此满足上述格式的都为合数。
    
    //只有满足  6n+1或6n+5 才有可能是素数。
    //同时6n+5可以看成6n-1的另一种形式。
    //即素数满足   6n-1和6n+1的形式 (除特例:2和3) 
    //即结论:一个数若是素数,则他一定在6倍数的两边(除特例:2和3) 

      故可以将上述代码再进行优化剪枝。

    bool prime(int n)  
    {
        if (n<=1)   //1即不是素数,又不是合数 
            return false;
        else if (n==2||n==3)
            return true;
        else if (n%6!=1&&n%6!=5)
            return false;
        int tmp=sqrt(n);
        for (int i=5;i<=tmp;i+=6)
            if (n%i==0||n%(i+2))
                return false;
        return true;
    }

    3.有的时候,面临的问题是询问次数过多,这里就需要通过一定的预处理,将询问的复杂度降为O(1)。

      显然这里的预处理就是    线性素数筛

     

    原理:n为素数,那么 i * n (i为非1的任意自然数)是非素数,即将 i * n 筛去。

    原理很简单,但是我们面临的优化是如何将一个数尽可能的只筛一次。  看下图操作

    如下图模拟线性素数筛步骤    :

    代码:

    const int MAX=10000010;   //线性素数筛的数据极限为1e7,大于这极限,则需要另寻他路 
    bool is_prime[MAX+10];
    int prime[MAX+10];
    int cnt=0;
    void init()
    {
        is_prime[1]=true;
        
        for (int i=2;i<=10000010;i++){
            if (is_prime[i]==false)  
                prime[++cnt]=i;
            for (int k=1;k<=cnt&&i*prime[k]<=10000010;k++){
                is_prime[i*prime[k]]=true;
                if (i%prime[k]==0)
                    break;
            }
        }
    }

    4.当我面临的数据超过了线性素数筛极限(1e7)的时候,那我如何处理?

      答案:再引进一个算法  Miller-Rabbin素数   ,    这是一个logn级别的算法  , 这是一个开挂的算法。

    //      在学习该算法之前,应当了解    费马小定理。  
    
    // 费马小定理:简单言之:   
    
    // 假设p的素数,   那么 pow(a,p-1)≡1(%p) ,即pow(a,p-1)%p = 1
    
    
    //那么如果有此式成立,是否p一定为质数?答案是否定的。但是,我们可以多测试几次,
    //即随机选取a值进行测试,提高准确率。测试次数越大,正确率越高。(有一点随机数味道,一般a的取值次数在30次左右就能判定)
    
    //优点:  算法数据极限可扩展到   int64 ,有点强。
    
    //缺点:  测试一次失败的概率为  1/4,   测试30次失败的概率为    (1/4)^30。   即并非正确率100% 
  • 相关阅读:
    牛客 Wannafly 挑战赛26D 禁书目录 排列组合 概率期望
    UOJ#269. 【清华集训2016】如何优雅地求和
    斯特林数 学习笔记
    AtCoder Grand Contest 006 (AGC006) C
    Codeforces 1045D Interstellar battle 概率期望
    Codeforces 1045A Last chance 网络流,线段树,线段树优化建图
    Codeforces 1053C Putting Boxes Together 树状数组
    Codeforces 109D String Transformation 字符串 哈希 KMP
    AtCoder Grand Contest 1~10 做题小记
    AtCoder Grand Contest 002 (AGC002) F
  • 原文地址:https://www.cnblogs.com/q1204675546/p/11294995.html
Copyright © 2020-2023  润新知