zoukankan      html  css  js  c++  java
  • 线性筛法(伪模板及。。。)

    ~(≧▽≦)/~啦啦啦

    主要讲解三种常用的筛法及其原理

    1.线性筛法:改进了埃氏筛法(埃拉托斯特尼筛法),保证了每一个数只被它最小的质因数筛去,避免了埃氏筛法的重复运行

    int check[N],prime[N],tot;
    void OULA(){
        for(int i=2;i<=n/2;i++){
            if(!check[i]){
                prime[tot++]=i;
            }for(int j=0;j<tot;j++){
                if(i*prime[j]>n) break;//判断越界
                check[i*prime[j]]=1;
                if(i%prime[j]==0) break;//保证最优
            }
        }
    }

    2.6倍原理

    题解 P3383 【【模板】线性筛素数】可以直接转到这个大佬博客阅读

    一个结论是大于5的质数一定出现在6的倍数的两侧

    大于5的数可以写成如下格式$6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1...$

    可以发现不是$6$的倍数的两侧的数都可以写成如下三种格式中的一种

    $2(3x+1),3(2x+1),2(3x+2)$,显然这些数都不是质数,然后再除去$6x$本身

    根据以上规律,判断质数可以以6个数为单元快进

    bool pd(int x){
        if(x==1) return 0;
        if(x==2||x==3) return 1;
        if(x%6!=1&&x%6!=5) return 0;
        int tmp=sqrt(x);
        for(int i=5;i<=tmp;i+=6)
            if(x%i==0||x%(i+2)==0) return 0;
        return 1;
    }

    3.Miller Rabin算法

    %%%大佬博客%%%

    总结要点,那么长的话就这么点儿东西

    1.费马小定理$a^{p-1}≡1(mod p)$,在$p$是质数的前提下,证明略

    满足$a^{p-1}≡1(mod p)$的数$p$不一定是素数,反例是卡迈克尔数

    2.二次探测定理

    若$p$为素数,$a^2≡1(modP)$,那么$a≡±1(modP)$

    证明没有看懂。。。咕咕咕

    3.算法流程

    将$p-1$分成$2^k+t$,当$p$是素数,$a^{2^k+t}≡1(mod p)$

    然后随机选择一个数,计算出$a^t$,让其不断自乘,然后结合二次探测定理判断

    自乘后的数$(mod p)=1$,但之前的数$(mod p)≠±1$,这个数就是合数

    若$p$通过一次测试,则$p$不是素数的概率为$25$%

    那么经过$t$轮测试,$p$不是素数的概率为$frac{1}{4^t}$

    我习惯用$2,3,5,7,11,13,17,19$这几个数进行判断

    虽然是基于概率的运算,但失败率几乎为0

    int n,m,test[10]={2,3,5,7,11,13,17};
    int pow(int a,int b,int mod){
        int s=1;
        for(;b;b>>=1,a=1ll*a*a%mod)
            if(b&1) s=1ll*s*a%mod;
        return s%mod;
    }
    bool pd(int P){
        if(P==1) return 0;
        int t=P-1,k=0;
        while(!(t&1)) k++,t>>=1;
        for(int i=0;i<4;i++){
            if(P==test[i]) return 1;
            int a=pow(test[i],t,P),nxt=a;
            for(int j=1;j<=k;j++){
                nxt=1ll*a*a%P;
                if(nxt==1&&a!=1&&a!=P-1) return 0;
                a=nxt;
            }
            if(a!=1) return 0;
        }
        return 1;
    }

    P3383 【模板】线性筛素数

    模板题

    P1835 素数密度_NOI导刊2011提高(04)

    区间筛法模板,大体思路是:筛出$sqrt(r)$内的素数,然后用这些素数去筛选$[l,r]$中的数

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    
    #define N 10000005
    #define LL long long 
    using namespace std;
    
    bool is_prime[N],is_prime_small[N];
    void segment_sieve(LL l,LL r){
        for(LL i=0;i*i<=r;i++)
            is_prime_small[i]=true;
        for(LL i=0;i<=r-l;i++)
            is_prime[i]=true;
        
        for(LL i=2;i*i<=r;i++){
            if(is_prime_small[i]){
                for(LL j=2*i;j*j<=r;j+=i)
                    is_prime_small[j]=false;
                for(LL j=max(2LL,(l+i-1)/i)*i;j<=r;j+=i)//保证j位于区间内
                    is_prime[j-l]=false;
            }
        }
    }
    
    LL l,r,ans;
    
    int main()
    {
        scanf("%lld%lld",&l,&r);
        segment_sieve(l,r);
        for(int i=0;i<=r-l;i++) if(is_prime[i]) ++ans; 
        
        printf("%lld
    ",ans);
        
        return 0;
    } 

    线性筛法的写法,怎么感觉一样呢?

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    
    #define N 5000000
    using namespace std;
    
    int prime[N],tot,ans;
    bool vis[N],ins[N];
    
    inline void OULA(int n){
        for(int i=2;i<=n;i++){
            if(!vis[i]) prime[++tot]=i;
            for(int j=1;j<=tot;j++){
                if(i*prime[j]>n) break;
                vis[prime[j]*i]=true;
                if(i%prime[j]==0) break;
            }
        }
    }
    
    int l,r;
    
    int main()
    {
        
        scanf("%d%d",&l,&r);
        
        OULA((int)ceil(sqrt(r)));
        
        for(int i=1;i<=tot;i++){
            if(prime[i]>r) break;
            int L=ceil(l*1.0/prime[i]),R=ceil(r*1.0/prime[i]);
            if(L==1) L=2;
            for(int j=L;j<=R&&prime[i]*j<=r;j++)
                ins[prime[i]*j-l+1]=1;
        }
        
        for(int i=1;i<=r-l+1;i++)
            if(!ins[i]) ++ans;
        
        printf("%d
    ",ans);
        return 0;
    }
    线性筛法
  • 相关阅读:
    vertical blank interrupt 和 horizontal blank interrupt解释
    X server和windows manager的关系
    Kconfig中的select和depends on
    Debugging the kernel using Ftrace part 3
    Kernel: printk's no_console_suspend
    sql分割函数|在网上找的看着挺好,谁的忘了
    Ajax处理函数模板
    新闻添加html页面
    页码控件源码|分页页码控件源码
    谷歌本地商户中心 |谷歌本地商户中心 介绍|谷歌本地商户中心 网址
  • 原文地址:https://www.cnblogs.com/song-/p/9764671.html
Copyright © 2011-2022 走看看