素数的分布
先曝上一道题:
ural 1343 Fairy Tale
Description
Input
Output
Sample Input
input | output |
---|---|
5 64631 |
646310554187 |
这道题看起来挺白痴的,因为第一遍做的时候,直接暴力枚举,竟然就能通过了。
AC代码如下:
1 #include <iostream> 2 using namespace std; 3 4 bool isprime(long long a){ 5 if(a<2) return 0; 6 for(long long i=2;i*i<=a;i++){ 7 if(a%i==0) return 0; 8 } 9 return 1; 10 } 11 12 int main(){ 13 int n; 14 long long x,t; 15 cin>>n; 16 if(n){ 17 cin>>t; 18 } 19 else { 20 t=0; 21 } 22 23 x=t; 24 for(int i=n+1;i<=12;i++){ 25 x=x*10; 26 } 27 28 for(long long i=x;;i++){ 29 if(isprime(i)) { 30 printf("%012I64d\n",i); 31 break; 32 return 0; 33 } 34 35 } 36 }
其实不然,细细想想如果碰到一个很大的区间都没有素数怎么办,那样的话,直接递增往后找的方法很容易超时。这时候,书本上素数分布定理就可以用得上了。
记π(x)为小于x的所有素数的个数,可以证明limx->正无穷 π(x)/(x/lnx)=1,这也就说明了一个现象,就是你如果随机测试一个大的n为数,它为素数的概率是可以预见的。
也就是说随机测试一个n位的数,总能在有限步骤内找到一个素数。事实上,经证明大概每找1.44个数,就能找到这样一个素数,这是很大的概率。 素数分布的这个性质,已经被广泛的应用于寻找n位大素数的工作,所以本题为了保证不超时,运用“随机生成的数”来测试是否为素数的方式会更加科学。
代码如下:
1 #include <iostream> 2 #include <ctime> 3 #include <algorithm> 4 using namespace std; 5 6 bool isprime(long long a){ 7 if(a<2) return 0; 8 for(long long i=2;i*i<=a;i++){ 9 if(a%i==0) return 0; 10 } 11 return 1; 12 } 13 14 int main(){ 15 int n; 16 long long x,t; 17 srand((unsigned)time(NULL)); 18 cin>>n; 19 if(n){ 20 cin>>t; 21 } 22 else { 23 t=0; 24 } 25 26 27 do{ 28 x=t; 29 for(int i=n;i<=11;i++){ 30 x=(x<<1)+(x<<3)+(long long)((rand()&15)%10); 31 } 32 }while(!isprime(x)); 33 34 printf("%012I64d\n",x); 35 36 }
另外还有一些素数比较有趣的分布的特点这里也做一下梳理:
1.任意两个相邻的正整数n和n+1中必有一个不是素数。额,这倒不如说n,n+1必有一个是偶数,显然没什么卵用。
2.越往后越稀疏:在正整数序列中,有任意长的区间中不含有素数。
对于大于等于2的整数n,连续n-1个整数n!+2,n!+3,n!+4.....n!+n都不是素数。
3.n,n+2均为素数的例子有很多,这样的一对素数成为孪生素数。
目前孪生素数的证明,最好的证明是由张益唐提出的方法经过改进后的方法,这个距离已经缩小到246。
4.p为素数,2p-1称为梅森数,素数2p-1称为梅森素数。也就是说2p-1不一定是素数
5.形如4n+3的素数有无线多个。这一点,在另一篇博客:“威尔逊定理”中有提到。