码一波求1-n之间素数的办法。。。。
硬刚解法–n,n/2
|
|
这是理所当然的想法,按照素数的定义,除了1和它本身没有其他的因数,就是素数。
这种解法的缺点就是循环规模n稍微大点,运行时间。。。
只需要简单思索就能考虑到,n的因数是成对出现的,如(2,n/2),(3,n/3)等等,因此只枚举i最大到sqr(n)即可退出循环。这里需要注意浮点误差,一般我们用:
|
|
硬刚解法估计只能在入门题中使用。。。也就是对于某些数据量小且n小的题目。。还是有奇效的//我就是在说你校的比赛题
emmm…但不是所有题都对菜鸡这么友好的。。我们还可以在时间上改进算法。
普通筛选法–埃拉托色尼筛法
基本思想:素数的倍数一定不是素数
实现方法:用一个长度为N+1的bool数组保存信息(0表示素数,1表示非素数),先假设所有的数都是素数(初始化为0),从第一个素数2开始,把2的倍数都标记为非素数(置为1),一直到大于N;然后进行下一趟,找到2后面的下一个素数3,进行同样的处理,直到最后,数组中依然为0的数即为素数。
说明:整数1特殊处理即可。
|
|
当然打表打一次就够了。。。判断n以内一个数是不是指数直接judge[]就可以了。
但是我们大概算一下就会发现时间复杂度也不少。。。比如1e8,就是1e8*(1/2+1/3+1/5+1/7+1/11+…..)循环次数,前三个数加起来就以及1e8了,还不算判断时间。。。emmm 当然慢也很好解释,比如说一个合数30030,它分别在(2,3,5,7,9,11,13)时筛了一共是七次。。。emmm….更大的就更不用说了。。。
能不能再给力点呢?
线性筛法–欧拉筛法
原理:每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度近似是O(n)
|
|
节省空间的写法(少一个bool数组):
容斥原理
1e8的情况是筛选法完全无法满足的,但是还是考虑a * b = c的情况,1e8只需要考虑10000以内的素数p[10000],然后每次先减去n / p[i],再加上n / (p[i] * p[j])再减去n / (p[i] * p[j] * p[k])以此类推…于是就可以得到正确结果了。
Meissel-Lehmer算法
最后介绍的这个算法可以说是黑科技级别的,它能够在3s内求出1e11之内的素数个数。据说还有在300ms内求出1e11的个数的。可以参考wiki里面原理。然后给出来自Codeforces 665F题目里面的代码。
|
|
引申–求欧拉函数
在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler’s totient function、φ函数、欧拉商数等。
//来自约三百年前的碾压
|
|
参考:
https://www.cnblogs.com/grubbyskyer/p/3852421.html
http://blog.csdn.net/snow_me/article/details/52588819