zoukankan      html  css  js  c++  java
  • P3383 【模板】线性筛素数

    P3383 【模板】线性筛素数

    埃氏筛->欧拉筛

    普通埃氏筛(O(nlognlogn))

    for (int i = 2; i <= n; i++)//注意终止条件
    {
        if(!notpri[i])
            for(int j = 2; j * i <= n; j++)
                notpri[i*j]=true;   
    }
    
    

    优化

    for (int i = 2; i <= n; i++)//到根号
    {
        if(!notpri[i])
            for(int j = i; j * i <= n; j++)//j从i开始,因为[2、3..i - 1] * i之前再筛[2、3..i - 1]时已经筛过
                notpri[i*j]=true;   
    }
    

    但这样还有重复!
    比如24,删2时、删3时、删4时,都删了一次!(12,8,6被优化省了)

    欧拉筛(线性筛)

    思想:让每个合数只被最小质因数筛去

    过程(摘自[_mliy](https://www.luogu.com.cn/blog/222223/solution-p3383))

    避免重复筛,应找到筛合数的一种原则:这个合数只会被它的最小质因数筛。这样能保证每个合数只会被筛一次。
    (运行过程)从 22 开始,22 加入 prime 数组,再从小到大枚举质数(现在只有 22),筛掉质数与 22 的乘积(44 被筛掉)。
    到了 33,33 加入 prime 数组,从小到大枚举质数(此时有 22,33),筛掉质数与 33 的乘积(66,99 被筛掉)。 到了 44,44 没加入 prime 数组,枚举质数(有22,33),筛掉 88 后,因为 4mod2=04mod2=0,触发退出条件。(不触发,就会筛掉 1212,而 12=2 imes 2 imes 312=2×2×3,又会被 22 和 66筛一次)
    以此类推,可做出一张表:

    ii 的值 质数表 筛去的数
    2 2 4
    3 2,3 6,9
    4 2,3 8
    5 2,3,5 10,15,25
    6 2,3,5 12
    7 2,3,5,7 14,21,28,35
    cdots⋯ cdots⋯ cdots⋯
    每个质数只被筛一次,复杂度变为 O(n)O(n) ,可以AC。

    理解(摘自彤云望月

    对于 i%prime[j] == 0 就break的解释 :当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。
    举个例子 :i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8 * 3 = 2 * 4 * 3 = 2 * 12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。

    for(int i = 2; i <= sqrt(n); i++)
    {
        if(!notpri[i])    pri[++len] = i;
        for (int j = 1; j <= len; j++)
        {
            notpri[i * pri[j]] = true;
            if(i % pri[j] == 0)    break;
        }
    }
    

    题目ACcode

    #include <cmath>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define N 100000010
    #define F(i,a,b) for(int i=a;i<=b;i++)
    
    using namespace std;
    
    int n, q, notpri[N], pri[10000000], k,len;
    
    void pre()
    {
    	for(int i = 2; i <= n; i++){
    		if(!notpri[i])	pri[++len] = i;
    		for(int j = 1; j <= len; j++){
    			if(i * pri[j] >= n)	break;
    			notpri[i * pri[j]] = 1;
    			if(i % pri[j] == 0)		break;
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d",&n ,&q);
    	pre();
    	while(q--){
    		scanf("%d",&k);
    		printf("%d
    ",pri[k]);
    	}
    //	cout << len << "**";
    	return 0;
    }
    

    反思

    此题做了两天,总是RE,找了好久才知道是i*pri[j]没判断<=n!!!

  • 相关阅读:
    【题解】Codeforces Round #600(Div.2)
    【题解】CF 1073 G. Another LCP
    【题解】CF 1129C. Morse Code
    【题解】CF 1200E. Compress Words
    Cpp Chapter 8: Adventures in Functions Part4
    Cpp Chapter 8: Adventures in Functions Part3
    Python Chapter 9: 使用Tkinter进行GUI程序设计 Exercise
    Python Chapter 9: 使用Tkinter进行GUI程序设计 Part 4
    Python Chapter 9: 使用Tkinter进行GUI程序设计 Part 3
    Python Chapter 9: 使用Tkinter进行GUI程序设计 Part 2
  • 原文地址:https://www.cnblogs.com/ZhengkunJia/p/12250939.html
Copyright © 2011-2022 走看看