• 詹氏筛法和詹欧筛法——撵爆线筛的强大筛法,算法史的骄傲


    先介绍一下伟大的发明人:
    ZZX,就读于广东省中山市纪念中学。
    曾获得多个奖项,是一个超强的OI选手。
    发明了两个改变世界的重要算法:詹筛詹增


    先说以前的筛法是发么打的。
    一开始,我们打的都是埃氏筛法。就是从前往后扫,遇到一个素数,就筛去它的倍数,打上标记。没有打上标记的就是素数。
    这个算法自然是很慢的,据说时间复杂度是O(nlnn)O(n ln n)
    于是我们就引进了欧拉筛法,也就是线筛,那么我们可以保证对于每个数,它们至多被筛一次,所以时间复杂度是O(n)O(n)的。
    线筛比前面的算法优秀很多,所以一般情况下,我们都会选择打线筛。
    可是,到此为止了吗?
    不,我们还有詹筛


    其实詹筛的时间复杂度并不优秀,它不是线性的。
    本质上它就是埃氏筛法的优化版本。
    n=108n=10^8的时候,在JZOJ上评测,詹筛比线筛快了大概50ms。
    如果这个nn可以大些,詹筛或许不如线筛,可是,你还能再大多少吗?在OI比赛当中,你的空间有多少,你的时间有多少?所以在OI比赛的时间和空间范围限制中,詹筛是撵爆线筛的。


    詹筛的思想其实很简单,就是在埃氏筛法当中,把22给拎出来单独考虑。
    显然除了22以外,其它的偶数都不是合数。在埃氏筛法的处理当中,与22有关的东西其实很多。
    于是就有了下面这个代码:

    	for (int i=3;i*i<=n;i+=2)
    		if (!inp[i])
    			for (int j=i*i;j<=n;j+=i<<1)
    				inp[j]=1;
    

    是不是特别短?
    这样我们就可以将标记数组给求出来,当然,这不包括偶数,在素数判定的时候我们要特判一下就好了。
    詹筛是不需要将素数表打出来的,如果要打出来,扫一遍就好了。
    或许不会比线筛优化多少,但是詹筛的代码太简洁了,看起来比线筛舒服很多。


    欧拉:我不服!量你个毛头小子,居然敢撵爆欧拉筛法。
    ZZX:行行行,我们结合起来好不好?
    于是有了下面的代码:

    	p[*p=1]=2;
    	for (int i=3;i<=n;i+=2){
    		if (!inp[i])
    			p[++*p]=i;
    		for (int j=2;j<=*p && i*p[j]<=n;++j){
    			inp[i*p[j]]=1;
    			if (!(i%p[j]))
    				break;
    		}
    	}
    

    这样就比线筛和原来的詹筛快多了哈哈哈……
    于是我们起名叫詹欧筛法
    欧拉笑嘻嘻地回到他的天堂去了,原先的詹筛就算是吸氧气都比不上詹欧筛法(处理素数表的情况下)!


    有一句话说得好:优化永无止境!
    所以说还可以再优化吗?
    吸一口臭氧
    不只是考虑22,也考虑33
    这似乎是一种不错的思路,但代码复杂度一定大很多,况且计算机是二进制的,用33可能会造成一些不好的常数影响。

    其实有一种比较好的优化:
    我们只需要存奇数,偶数的标记数组是可以不需要的。
    那么就变成这样:

    	p[*p=1]=2;
    	for (int i=3;i<=n;i+=2){
    		if (!inp[i>>1])
    			p[++*p]=i;
    		for (int j=2;j<=*p && i*p[j]<=n;++j){
    			inp[i*p[j]>>1]=1;
    			if (!(i%p[j]))
    				break;
    		}
    	}
    

    这样可以将标记数组的空间减半,并且时间上优化约40ms。


    不过在有些时候我们利用筛法求的东西不只是素数,可能还有什么μmuϕphi之类的。
    下面是求最小质因数的例子。

    	mp[2]=2,p[*p=1]=2;
    	for (int i=3;i<=n;i+=2){
    		if (!mp[i])
    			mp[i]=i,p[++*p]=i;
    		for (int j=2;j<=mp[i] && i*p[j]<=n;++j)
    			mp[i*p[j]]=j;
    	}
    

    这个程序比上面的周筛法(连读)慢,但是它可以求出最小的质因数。
    至于其它的……那就不在这里说明了。

  • 相关阅读:
    C#代码也VB
    Flash/Flex学习笔记(9):ActionScript3.0与Javascript的相互调用
    原来Silverlight 4中是可以玩UDP的!
    Flash/Flex学习笔记(20):贝塞尔曲线
    Flash/Flex学习笔记(16):如何做自定义Loading加载其它swf
    AS3:让人叹为观止的Flash作品
    Flash/Flex学习笔记(10):FMS 3.5之Hello World!
    Flash/Flex学习笔记(12):FMS 3.5之如何做视频实时直播
    Flash/Flex学习笔记(28):动态文本的滚动控制
    Flash/Flex学习笔记(18):画线及三角函数的基本使用
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145204.html
Copyright © 2020-2023  润新知