线性筛选法求素数
程序员文章站
2024-03-21 15:11:04
...
普通求法:
#include<stdio.h>
int main()
{
int i, n;
while (scanf("%d", &n) == 1)
{
for (i = 2;i <
n;i++)
if (n % i == 0)
break;
if (i == n)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
这个缺点就是如果n稍微大点运行的时间就很大
在普通的基础上改进方法(sqrt(n)):
#include<stdio.h>
#include<math.h>
int main()
{
int i, n, x;
while (scanf("%d", &n) == 1)
{
x= (int)sqrt(n);
for (i = 2;i <=x;i++)
if (n % i == 0)
break;
if (i > x)
printf("Yes\n");
else
printf("NO\n");
}
return 0;
}
用的sqrt,效率提高了,但是还是不够理想
于是我们有线性筛法(欧拉筛法):
原理:素数的倍数一定不是素数。
我们可以用一个长度为n+1的数组来存储信息(这种用另一个数组来保存信息的方法很常见也很有用),首先将所有的数字全初始化为0(素数),再将数字1与第一个素数2标记为1(非素数)从素数2开始将所有小于n的2的倍数都标记为1;继续该过程,将素数3的倍数筛掉,到循环结束时,标记仍为0的数就是素数。
//primer用来保存得到的素数
memset(check , 0 , sizeof(check) );
check[1] = 1;
int sum = 0,i,j;
for(i = 2;i <= n; i++)
{
if(!check[i])
primer[sum++]
= i;
for(j
= i+1;j <= n;j += i)
check[i]
= 1;
}
仔细分析这个算法的优化已经很好了,但是有些数字被重复使用了
于是乎真正的欧拉筛选来了
欧拉筛选保证一个合数只会被他最小的质数因子筛序一次
代码如下
check[1] = 1;
int sum =0, i, j;
for (i =
2;i <= n;i++)
{
if (!check[i])
primer[sum++]= i;
for (j = 0;j <sum;j++)
{
if (i * primer[j] >n)
break;
check[i* primer[j]] = 1;
if (i % primer[j] ==0)
break;
}
}
思路:
1.用线性筛法求出N范围内的素数保存在primer中(友情提示:大数组最好放在main函数之外定义,其他的题最好也是这样。为什么?百度“栈帧”,你就知道)
2.对这M组数据,用二分查找对比primer。
#include <stdio.h>
int n,w, primer[1000010],tot,s,i;
int check[100000010];
int main()
{
scanf("%d%d",&n,&w);
for(i = 2; i <= n; i++)
{
if(check[i] == 0) primer[++tot] = i;
for(int j = 1; (j <= tot) && (i*primer[j] <= n); j++)
{
check[i * primer[j]] = 1;
if(i % primer[j] == 0) break;
}
}
while(w--)
{
scanf("%d",&s);
i = 1;
int j = tot, mid;
while(i <= j)
{
mid = (i + j) / 2;
if(s == primer[mid])
{
printf("Yes\n");
break;
}
else if(s < primer[mid]) j = mid - 1;
else i = mid + 1;
}
if(s != primer[mid]) printf("No\n");
}
return 0;
}