素数筛选法

素数筛选法差不多是打标,用前面确定的质数筛选掉后面的合数,然后遍历下来所有的合数都被筛选掉了,剩下的都是素数。

int vis[MAXN] = {0,0};

for(int i = 2; i <= n; i++)
    for(int j = i*2; j <= n; j+=i)
        vis[j] = 1;

这是没有优化的素数筛选法,也已经很快了,时间复杂度是n log n。

m = sqrt(n+0.5)

在m~n之间的数,只要在前m个数中没有质因子,那么这个数肯定就是质数:一个数a只要有因子,那么2~sqrt(a)之间一定有因子,那么也就是说m~n之间的数只要有因子,那么在2~m之间一定存在它的因子

优化后的素数筛选法:

    int m = sqrt(n+0.5);  ///素数筛选法的优化,在后sqrt(n)的数中,遍历的前sqrt(n)中没有这个数的(质)因子,那么这个数就是一个质数

    memset(vis, 0, sizeof(vis));
    for(int i = 2; i <= m; i++)
        if(!vis[i])      ///素数筛选法的优化,不是=质数就不用更新后面的数了,因为前面的质数已经将它的这些倍数更新了
            for(int j = i*i; j <= n; j += i)  ///i*i也是一个优化,i * x中x < i的数已经被更新过了
                vis[j] = 1;

用素数筛选法做的一道题目,大概题意就是:求x ~ n之间没有平方因子的数的个数

思路:用素数筛选法求出2~sqrt(n+0.5)中的素数,然后类似于筛选法,用2~sqrt(n+0.5)中的素数筛选掉x~n之间含有素数的平方的数就OK了

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;


int vis[10000000];
int ans[10000005];
int main()
{
    int n, sum = 0, x;

    scanf("%d%d", &x, &n);
    int m = sqrt(n+0.5);  ///素数筛选法的优化,在后sqrt(n)的数中,遍历的前sqrt(n)中没有这个数的(质)因子,那么这个数就是一个质数

    memset(vis, 0, sizeof(vis));
    memset(ans, 0, sizeof(ans));
    for(int i = 2; i <= m; i++)
        if(!vis[i])      ///素数筛选法的优化,不是=质数就不用更新后面的数了,因为前面的质数已经将它的这些倍数更新了
            for(int j = i*i; j <= n; j += i)  ///i*i也是一个优化,i * x中x < i的数已经被更新过了
                vis[j] = 1;



    for(int i = 2; i <= m; i++)
    {
        if(!vis[i])
        {
            int p, p0 = i*i;
            p = x/p0*p0;
            if(p != x) p+= i*i;
            for(int j = p; j <= n-x; j+=p0)
            {
                ans[j - x] = 1;
            }
        }

    }
    for(int i = 0; i <= n-x; i++)
        if(!ans[i])
            sum++;
    printf("%d", sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/look_poet_of_water/article/details/81320064