一.引言:
让我们列举以下100以内的素数:
2、3、5、7、11、13、17、19、23、29、31、37、41、43、47、53、59、61、67、71、73、79、83、89、97
除了2和3以外,我们可以发现这样一个规律——其实每一个素数都可以表示为含有2和3的关系式,比如:
2 = breakI
3 = breakII
7 = 2*3+1;
11 = 2*3*2-1;
13 = 2*3*2+1;
17 = 2*3*3-1;
19 = 2*3*3+1;
23 = 2*3*4-1;
29 = 2*3*5-1;
31 = 2*3*4+1;
37 = 2*3*6+1;
41 = 2*3*7-1;
43 = 2*3*7+1;
47 = 2*3*8-1;
53 = 2*3*9-1;
59 = 2*3*10-1;
61 = 2*3*10+1;
67 = 2*3*11+1;
71 = 2*3*12-1;
73 = 2*3*12+1;
79 = 2*3*13+1;
83 = 2*3*14-1;
89 = 2*3*15-1;
97 = 2*3*16+1;
如果拓展到n
那就是
I:
(n + 1) % 6 == 0;
II:
(n - 1) % 6 == 0;
二.总结:
总结一下:除了2和3外,其余素数都与6的倍数相邻,这些素数都满足6n±1,也就是说这些素数都分布在6的倍数的邻数上。总结为一句话:大于等于5的质数一定和6的倍数相邻。例如:5、7, 11、13、17等。但是与6的倍数相邻的不一定是素数,有可能是6倍邻数的倍数,例如25、35、49,这些数就分别是5,7的倍数。
所以:这是个trivial的素数分布特征,因模6的余数中只有1和5与6互素,故从5开始的素数必与6的倍数相邻。
三.证明:
如何从数学的角度进行证明?
我们不难发现,对于一列公差为1的数,我们可以任意的对其分割周期
所以说我们的递归边界为2和3(即上列举数字时的break I和break II),那也就是下一次的周期应该是2*3=6。
一般的
就会有6n,6n+1,6n+2,6n+3,6n+4,6n+5,6n+6(其实就是6n)
我们来看
6n,6n+2,6n+4,6n+6一定为偶数,所以不是素数
同样6n+3也一定是3的倍数
所以只剩下了6n+1和6n+5
想一个例外:
6n+5可能是5的倍数怎么办?(如35)
所以说满足6n+1或6n-5的数和一个数是素数是必要不充分条件
所以,我错了嘛?
没有,既然如此,在循环里去除就行了
或者说,在我们遍历6n+1和6n+5时只需要额外的操作一下就可以了,例如2*3*4+1=25,但是25并不是素数
相似的,还有2*3*6-1=35,2*3*8+1=49
那么这些数满足什么式子呢?
不难发现,这几个数都是(6m±1)*(6n±1);的形式
所以在循环里只需要排除掉就可以了
如此,定义一个flag,在满足上列条件时flag = false;
所以接下来就是设计代码了:
第一步:先判断是否为6倍邻数,如果是则执行第二步;
第二步:判断这个数是否为6倍邻数的倍数以及是否满足如上条件,如若不是则这个数为素数
得证!
代码
#include<bits/stdc++.h>//万能头文件库,源代码的形式
using namespace std;//启动内存
bool check(long long n)//定义函数check,bool意为这个函数的返回值只有true或false
{
if (n == 1)
return false;
else
if (n == 2 || n == 3)
return true;
else
if (n % 6 != 1 && n % 6 != 5)
return false;
for(int i = 5;i <= sqrt(n);i += 6)
{
if (n % i == 0 || n % (i + 2) == 0)
return false;
}
return true;//判断条件
}
int main()
{
long long min,max;//定义变量long long型,确定判断范围
long long sum = 0;
cin >> min >> max;//输入
for(int i = min;i <= max;i ++)//循环,从min到max每个判断一遍
{
if(check(i) == true)//如果为true为素数
{
cout << i << " ";//输出素数
sum ++;//累加器自+1sum ++ 等价于sum = sum + 1
}
}
cout << sum;//输出一共有几个
return 0;//结束程序
}//一个=是复制,两个=(==)是相等
总结
时间复杂度
应该是O(n^3/2)
在100000000时比欧拉筛慢1-2秒,但是结果符合,所以应该没有什么问题。
所以优点就是易于理解,然后缺点就是代码会慢。
注释
素数:即质数,即最大公约数只有自己和1的数
Trivial:平凡,在“关于双周期函数的第二篇论文(Deuxième mémoire sur les fonctions doublement périodiques)”中,<<纯粹与应用数学杂志>>(Journal de Mathématiques Pures et Appliquées),tom.xix.(1854年),第193-208页,Cayley写道,“我首先假设 2k + 1 等于 1,这个变换可以说是平凡的。” [我首先假设 2 k + 1 可能等于 1,这是一种可以称之为“平凡”的变换(I first suppose that 2k + 1 may be equal to unity, a transformation that one could call “trivial”)。]||例子:我们称齐次线性方程组AX = 0的通解x = 0为平凡解
%:OI术语同数学中mod,意为取余数运算,例如6%2==0
遍历:OI术语是指沿着某条路径,依次对每个数据点均做一次访问
递归:函数的定义中使用函数自身的方法,在计算机科学中还额外指一种通过重复将问题分解为同类的子问题而解决问题的方法。描述+边界:例:

Flag:可以理解为标签
时间复杂度:OI术语,衡量一个算法的快慢,一定要考虑数据规模的大小。所谓数据规模,一般指输入的数字个数、输入中给出的图的点数与边数等等。一般来说,数据规模越大,算法的用时就越长。而在算法竞赛中,我们衡量一个算法的效率时,最重要的不是看它在某个数据规模下的用时,而是看它的用时随数据规模而增长的趋势,即 时间复杂度。
应用:
致谢: www.lib.ox.ac.uk
www.google.com
www.oi-wiki.org
1260



被折叠的 条评论
为什么被折叠?



