素数筛选法差不多是打标,用前面确定的质数筛选掉后面的合数,然后遍历下来所有的合数都被筛选掉了,剩下的都是素数。
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
#include
#include
#include
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;
}