• 【模板】素数筛法


    (好-----快------)

    素数是什么就不用介绍了吧。。。先介绍判断素数的方法

    判断素数

    先看朴素算法

    for (i=2;i<n;i++) 
    if (n%i==0) break;
    if (i==n) printf(“n is prime”);
    else printf(“n is not prime”);

    (真的好朴素。。)

    用时O(n)

    (肯定不行啊,吃枣药丸的。。)

    怎么优化呢?

    不难发现,如果a是n的约数,那么n/a也是n的约数

    所以就有以下代码:

    n2=int(sqrt(n)+0.5);
    for (i=2;i<=n2;i++) if (n%i==0) break;
    if (i>n2) printf(“n is prime”);
    else printf(“n is not prime”);

    这个用时O(n^0.5)

    一般使用的话这样其实差不多了。。(其实有一个更快的只是我不会。。)

    筛选素数

    进入正题啦!

    目标:

    尽量快的找出1---n之间的所有素数

    朴素算法:

    for(int i=2;i<=n;i++)
        {
            for(int j=2;j<=sqrt(i);j++)
            {
                if(i%j==0)
                {
                   flag=1;
                   break;
                }
            }
            if(!flag)
            cout<<i<<" ";
            flag=0;
        } 

    其实也不是很朴素啦。。用了上面介绍的优化,但是速度还是很慢

    怎么优化呢?

    对于任意数a,a所有的整数倍都是合数

    int flag[2333]; int prime[2333]; int primes;
    for (int i=2;i<=n;i++) flag[i]=0;
    for (int i=2;i<=n;i++) for (int j=i*i;j<=n;j+=i) flag[j]=1; //表示j被标记为合数
    for (int i=2;i<=n;i++) if (flag[i]==0) prime[primes++]=i;

    有了这个想法,还可以继续优化

    对于质数a,a的所有整数倍都是合数

    int flag[2333]; int prime[2333]; int primes;
    for (int i=2;i<=n;i++) 
    if (flag[i]==0) 
    {
        prime[primes++]=i;
        for (int j=i*i;j<=n;j+=i) flag[j]=1;
    }

    还可以继续优化吗?

    其实还可以进一步优化,只要每个合数都只被自己能整除的最小的质数标记一次,速度就可以达到线性级别(好快!)

    说白了就是每个质数尽可能多的标记合数(也不是很好懂的样子?)

    看代码吧:

    #include<iostream>
    using namespace std;
    int prime[100001];
    int f[100001],primes;
    int n;
    int main()
    {
        cin>>n;
        for(int i=2;i<=n;i++)
        {
            if(!f[i])//如果i还没有被标记,就说明i是新出现的素数 
            {
                prime[primes]=i;
                f[i]=-1;
                primes++;//标记 
            }
            for(int j=0;j<primes;j++)//枚举当前找到的所有素数 
            {
                int ans=prime[j]*i;
                if(ans>n)
                break;//越界就停止 
                f[ans]=j+1;//标记每一个含有prime[j] 这个因数的合数 
                if(i%prime[j]==0)//如果当前 i可以整除prime[j],就说明后面的prime[j]都不会是ans的最小质因子了 
                break;
            }
        }
        cout<<primes<<endl;//素数个数 
        for(int i=0;i<primes;i++)
        {
            cout<<prime[i]<<" ";//所有素数 
        }
        return 0;
    } 

    (RP++!)

  • 相关阅读:
    bzoj 2818 Gcd(欧拉函数 | 莫比乌斯反演)
    bzoj 2186 [Sdoi2008]沙拉公主的困惑(欧拉函数,逆元)
    bzoj 2393 Cirno的完美算数教室(容斥原理+搜索)
    c3p0 连接池配置
    Hibernate连接池断开自动重连
    Oracle ASM注意事项
    JAVA如何获得数据库的字段及字段类型
    在引入的css或者js文件后面加参数的作用
    JAVA注解
    Linux软连接和硬链接
  • 原文地址:https://www.cnblogs.com/Daz-Os0619/p/11469775.html
Copyright © 2020-2023  润新知