威尔逊定理
2015-10-21 09:39
155 查看
讲解过素数判定之后,老师又讲了一个威尔逊定理,挺有意思的,竟然是判断素数的定理,还是充分必要条件!。。然并卵,判定增长是指数级的,并没有什么实用价值。。不过还是总结一下这个学院派的定理吧。。。。也不知道猴年马月能用上,不过多知道一条定理总是好的!
定理内容:当( p -1 )! ≡ -1 ( mod p ) 时,p为素数。其逆定理也正确。定理的证明这里从略,下面主要讲一下它的应用。
根据威尔逊定理,想要判断一个数是否是素数,只需要从1到比该数小1的数统统乘起来,然后加1,得到的和如果能整除该数,则该数就是一个素数。这个判定方法虽然是判定素数的充要条件,但是并没有太多的实用价值:其判定时需要的计算量成指数级增长。例如判定41243是否是一个素数,就需要计算1*2*3*4...41241*41242.且不说乘法计算下来的时间问题了,就是想找一个空间存储计算得到的值就是一个几乎难以解决的问题。
不过关于威尔逊定理有一些推论:形如4x+1的质数,一定可以表示为两个整数的平方和,而且表达方法是唯一的;
而形如4x-1的质数,不可能是两个整数的平方和。
-----------------------------------------
质数 4x+1型=a2+b2 4x-1型
3 4×1-1
5 4×1+1=22+12
7 4×2-1
11 4×3-1
13 4×3+1=32+22
17 4×4+1=42+12
19 4×5-1
23 4×6-1
29 4×7+1=52+22
31 4×8-1
37 4×9+1=62+12
41 4×10+1=52+42
43 4×11-1
------------------------------------------
我们知道大于3的奇数都能写成4x+1和4x-1(其实就是4k+3) 的形式,所以,威尔逊定理的这个推论,覆盖了2以外所有的质数!这大大的增加了人们对素数的认识程度!
曝一道习题吧:威尔逊定理的应用。
HDU 2973 YAPTCHA
此题运用威尔逊定理分析之后,实际上求得是1~n之间素数的个数,由于题目中t的值较大,这里可以先将1~106之间的素数用筛法筛出来,然后直接线性时间内输出结果即可。
代码如下:
定理内容:当( p -1 )! ≡ -1 ( mod p ) 时,p为素数。其逆定理也正确。定理的证明这里从略,下面主要讲一下它的应用。
根据威尔逊定理,想要判断一个数是否是素数,只需要从1到比该数小1的数统统乘起来,然后加1,得到的和如果能整除该数,则该数就是一个素数。这个判定方法虽然是判定素数的充要条件,但是并没有太多的实用价值:其判定时需要的计算量成指数级增长。例如判定41243是否是一个素数,就需要计算1*2*3*4...41241*41242.且不说乘法计算下来的时间问题了,就是想找一个空间存储计算得到的值就是一个几乎难以解决的问题。
不过关于威尔逊定理有一些推论:形如4x+1的质数,一定可以表示为两个整数的平方和,而且表达方法是唯一的;
而形如4x-1的质数,不可能是两个整数的平方和。
-----------------------------------------
质数 4x+1型=a2+b2 4x-1型
3 4×1-1
5 4×1+1=22+12
7 4×2-1
11 4×3-1
13 4×3+1=32+22
17 4×4+1=42+12
19 4×5-1
23 4×6-1
29 4×7+1=52+22
31 4×8-1
37 4×9+1=62+12
41 4×10+1=52+42
43 4×11-1
------------------------------------------
我们知道大于3的奇数都能写成4x+1和4x-1(其实就是4k+3) 的形式,所以,威尔逊定理的这个推论,覆盖了2以外所有的质数!这大大的增加了人们对素数的认识程度!
曝一道习题吧:威尔逊定理的应用。
HDU 2973 YAPTCHA
此题运用威尔逊定理分析之后,实际上求得是1~n之间素数的个数,由于题目中t的值较大,这里可以先将1~106之间的素数用筛法筛出来,然后直接线性时间内输出结果即可。
代码如下:
#include <cstdio> #include <cstring> const int MAXN = 1e6+10; bool u[3*MAXN]; //若i为素数则标记为1.;之所以乘3,是为了保证筛得的数够u[3*i+7]用 int prime[3*MAXN], cnt = 0; //cnt记录素数个数 int ans[MAXN], t, n; int main() { memset(u, true, sizeof(u)); //这一步的核心是筛法求素数 for(int i=2; i<3*MAXN; ++i) { if(u[i]) prime[cnt++] = i; //用prime数组记录素数 for(int j=0; j<cnt && i*prime[j]<3*MAXN; ++j) { u[i*prime[j]] = false; //把素数prime[j]的i倍的数全部筛掉 if(0 == i%prime[j]) break;//符合该条件的i已经标志prime[i]=0,故无需重复标记 } } //这一步的核心是威尔逊定理,可以推出简单化结论 ans[0] = 0; for(int i=1; i<MAXN; ++i) { ans[i] = ans[i-1] + u[3*i+7];//若3i+7为素数,则该项的值为1,就在Sn=S(n-1)+1. } scanf("%d", &t); while(t--) { scanf("%d", &n); printf("%d\n", ans ); } return 0; }
相关文章推荐
- cardview使用笔记
- Android Studio解决unspecified on project app resolves to an APK archive which is not supported
- 轻松学习Ionic (一) 搭建开发环境,并创建工程
- 第一章 基本语法-2运算符
- Tomcat 长连接与短连接性能测试
- iOS中容易忽略的小细节
- C++11 的一些有用的特性1 VS2012可支持
- 一个神经网络模式识别的例子------螃蟹识别
- Java中类继承、接口实现的一些细节(长期更新)
- Android Java混淆(ProGuard)
- 差不多先生
- Linux基础学习3
- 分享九:php易混淆的语法
- CoordinatorLayout与滚动的处理
- IOS-UITableView
- TSS TR
- mouseenter与mouseover事件的区别与应用
- HIVE入门_2
- 设计模式之观察者模式
- EBS密码安全的几个参数