关于素数筛选,ACM中常用的有两种方法:埃拉托色尼(Eratosthenes)筛法( 复杂度为O( nloglogn ) )和快速筛选法(也叫线性筛法,复杂度为O(n))。
先说第一种筛法:
//埃拉托色尼(Eratosthenes)筛选法: #define N 10000 bool prime[N]; //纪录N以内的素数 int p[N]; //p[i]是第i个素数 int k=0; //纪录素数的个数 void isprime() { long long i,j; memset(prime,true,sizeof(prime)); for(i=2; i<N; i++) { if(prime[i]) { p[k++]=i; for(j=i*i; j<N; j+=i) prime[j]=false; } } }
这种筛法在n为10^6甚至更大的时候可以快速求出1到n之间的所有素数,把之前找出的素数的倍数标记为合数,没被标记的自然为素数,时间复杂度为O(nloglogn),这种方法在解决一般的素数问题中足以。
但不得不说另一种时间复杂度为O(n)的快速筛选法:
//线性筛法: bool isPrime[N]; int prime[N]; int total; void makePrime() { memset(isPrime,true,sizeof(isPrime)); memset(prime,0,sizeof(prime)); for(int i=2; i<=N; i++) { if(isPrime[i]) prime[total++]=i; for(int j=0; j<total && i*prime[j]<=N; j++) { isPrime[i*prime[j]]=false; if(i%prime[j]==0) break; } } }
它与埃拉托色尼筛法类似,但它保证使任何一个合数,只被它的最小质因数标记过一次,所以整个算法是线性的。但就实际问题而言,两者在运算速度上没有太大差别,大家可大致了解一下。
下面我们来看一下 HDU2710:筛选出1到n之间的所有数的最大最大质因数:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2710
实现代码如下:
#include <cstdio> #include <iostream> using namespace std; const int maxn=20005; int max_factor[maxn]= {0,1}; void init() { for(int i=2; i<=maxn; i++) { if(!max_factor[i]) for(int j=i; j<=maxn; j+=i) max_factor[j]=i; } } int main() { init(); int n,num,ans; while(scanf("%d",&n)!=-1) { int ans_f=0; for(int i=0; i<n; i++) { scanf("%d",&num); if(ans_f<max_factor[num]) { ans_f=max_factor[num]; ans=num; } } printf("%d\n",ans); //printf("ans_f=%d\n",ans_f); } return 0; }