进阶必备:素数筛法(欧拉,埃氏筛法)
筛选素数其实有两种比较高效的算法可以提供选用,分别是:Eratosthenes筛选法与欧拉筛选法。但是欧拉算法的普适性比较高,所以这里就只介绍欧拉函数的算法。
筛选的范围较小的话,欧拉算法,数据较大,埃氏筛法,所以埃氏筛法一定要掌握,以后可以统一用埃氏筛法。
【埃氏筛法】
const int maxn=10000005; int prime[maxn]; int vis[maxn]; int cnt = 0; void sieve()//返回n以内的素数 { cnt=0; for(int i=0;i<=maxn;i++) vis[i]=1; vis[0]=vis[1]=0; for(int i=2;i<=maxn;i++) if(vis[i]) { prime[cnt++]=i; for(int j=2*i;j<=maxn;j+=i) vis[j]=0; } }
筛选10000000以内的素数,埃氏筛法的平均时间是0.756秒,而欧拉算法达到了2.2秒多,所以算法的复杂度埃氏筛法远远优于欧拉。
还有一种筛选法的速度比埃氏筛法还要快一些,它的10000000以内的时间为0.721秒。代码贴上来作为参考:
const int maxn=10000005; int prime[maxn]; int vis[maxn]; int check[maxn]; int cnt = 0; void init() { int cnt=0; check[0]=check[1]=1; for(int i=2;i<maxn;i++) { if(!check[i]) { prime[cnt++]=i; vis[i]=1; } for(int j=0;j<cnt;j++) { if(prime[j]*i>=maxn) break; check[i*prime[j]]=1; if(i%prime[j]==0) break; } } }
以上两种算法,执行完毕之后,vis数组里面的如果为1,表示为素数,为0则为合数。prime数组里面保存的则是素数集,cnt表示素数的个数。还有重要的一点就是对于卡时间的题,注意不要使用cin,cout这类的输入输出了,不然时间会爆掉,比如下面牛客网的这题,如果不用scanf还有printf的话,就是过不了的,所以养成好习惯的话,以后应当减少cin,cout的使用,实在无法避免使用的话,可以试试加上ios::sync_with_stdio(false); (因为即使加上这句话,cin/cout体系还是没有scanf/printf快)
【题源】牛客网
欧拉筛法因为不具有普适性,时间优化不够好,所以在这里不贴上来了,有兴趣的读者可以自行百度。
2019/4/23 二改
posted on 2018-04-20 14:19 superhero11 阅读(1204) 评论(0) 编辑 收藏 举报