原
ACM素数打表(模版)
2018年03月28日 00:03:37 Doneone_ 阅读数 377
第一次写博客。
今天学了两个很简单的定理,老是忘记细看,今天可算看了下。
其中一个是
素数打表的优化
首先先理解了简单的埃筛法;
埃筛法就是把表中全部数为素数的倍数一个个筛除,最后只有素数留在表中。
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 100000
int check[maxn]={0};
int prime[maxn]={0};
int main()
{
int n, cnt = 0;
while(~scanf("%d",&n))
{
int num=0;
memset(check,0,sizeof(check));
for(int i=2;i<=n;i++)
{
if(check[i]==0)
prime[num++]=i;
for(int j=i+i;j<=n;j+=i) //素数的倍数全部标记
{
check[j]=1;
}
}
for(int i=0;i<num;i++)
printf("%d ",prime[i]);
} //埃筛法
return 0;
}
时间复杂度为O(n loglog n);
接下来是更为优化的欧拉线性筛法(时间复杂度为O(n))
/求小于等于n的素数的个数/
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
int n, cnt = 0;
int prime[100001];//存素数
bool vis[100001];//保证不做素数的倍数
scanf("%d", &n);
memset(vis, false, sizeof(vis));//初始化
memset(prime, 0, sizeof(prime));
for(int i = 2; i <= n; i++)
{
if(!vis[i])//不是目前找到的素数的倍数
prime[cnt++] = i;//找到素数~
for(int j = 0; j<cnt && i*prime[j]<=n; j++)
{
vis[i*prime[j]] = true;//找到的素数的倍数不访问
if(i % prime[j] == 0) break;//关键!!!!
}
}
printf("%d\n", cnt);
return 0;
}
if(i % prime[j] == 0) break;←_←这一步比较难理解
解释:
首先,任何合数都能表示成多个素数的积。所以,任何的合数肯定有一个最小质因子。我们通过这个最小质因子就可以判断什么时候不用继续筛下去了。
当i是prime[j]的整数倍时(i % prime[j] == 0),i*prime[j+1]肯定被筛过,跳出循环。
因为i可以看做prime[j]*某个数X, i*prime[j+1]就可以看做 prime[j]*x*prime[j+1] 。而 prime[j] 必定小于 prime[j+1],
所以 iprime[j+1] 这个合数已经被Xprime[j](prime[j]是这个合数的最小质因子)筛掉,就不用再做了
也就是:
i=prime[j]*x;
合数=i*prime[j+1]=i*prime[j]*x; //prime[j]是合数的最小质因子!
同时我们可以发现在满足程序里的两个条件的时候,prime[j]必定是prime[j]*i的最小质因子。这个性质在某些题里可以用到。
/*参考了http://www.cnblogs.com/A-S-KirigiriKyoko/articles/6034572.html