数论篇之素数详解_数学素数

数论篇之素数详解_数学素数一.素数的定义基本定义:在大于1的自然数中,除了1和它本身以外不再有其他因数

一.素数的定义

基本定义: 在大于1的自然数中,除了1和它本身以外不再有其他因数。

在这里插入图片描述
(此图可省略)

注意:1既不是素数也不是合数;2是最小的素数,也是唯一的偶素数。素数的个数是无限的.

二. 有关素数的定理

一:算数基本定理

任何一个大于1的正整数都能被唯一分解为有限个质数的乘积,可写作:

N=a1c1 a2c2a3c3……amcm

其中ci都是正整数,ai都是素数且满足a1<a2<a3……<am

(此定理不多解释,只能意会,不能言传。)(那你还好意思称详解)

二:威尔逊定理

如果p为素数,则 ( p -1 )! ≡ -1 ( mod p )
威尔逊定理的逆定理也成立,即如果 ( p -1 )! ≡ -1 ( mod p ),则 p为素数。
(p-1)!+1一定是p的倍数
(此定理知道就行,在初等数论中,由于阶乘爆炸性增长,所以意义不大。貌似此定理不大出现)
证明的话,蒟蒻不会。但检验还是可以的
检验

 scanf("%d",&p); int ans=1; for(register int i=1;i<=p-1;i++){//计算p-1的阶乘 ans=(ans*i)%p; } printf("%d\n",(ans+p)%p); printf("%d",(p-1)%p); 

多试上几组,明显是可行的
在这里插入图片描述
在这里插入图片描述

其中首行为是不是质数。然后挨个输出

三.费马小定理

(这个定理貌似不陌生)
若p为素数,a为正整数,且a和p互质(牢记使用条件),则a^(p-1)≡1(mod p)
(讲真的,此定理我不想证明;但毕竟不能完全背离详解的题目吧。)
证明
首先,p-1个整数,a,2a,3a,……,(p-1)a中没有一个是p的倍数,因为p为素数,a为正整数,且a和p互质。

其次,a,2a,3a……,(p-1)a中没有任何两个同余与mod p的。(我觉得这很显然。。。但我不会说为么。。。。)

于是:a,2a,3a……(p-1)a 对mod p的同余既不为0(缘于首先),也没有两个同余相同(缘于其次),因此,这p-1个数对mod p的同余一定是1,2,3,……(p-1)的某一种排列(因为,同余不为零也不相同,但在mod p的情况下,结果只有0~p-1)

即:a × 2a × 3a……×(p-1)a mod p≡1×2×3×……×(p-1)(mod p) 在上述条件的情况下,这必成立~~(这不多说)~~

然后我们进行化简
即:ap-1× (p-1)!≡(p-1)! (mod p)

我们根据威尔逊定理(上一个定理),因为p是素数,所以(p-1)!和p互质(因为威尔逊定理(p-1)!+1是p的倍数,不妨设(p-1)!+1=mp,则(p-1)!=mp-1,mp-1和p互质)。所以我们可以直接约去(p-1)!。

然后我们便证明了伟大的费马小定理.(感觉身体被掏空。。。。。。)

三.素数的判定

法一:试除法

如果一个数N为非素数,则存在一个能整除N的数K,其中2<=K<=sqrt(N)

证明: 我们利用反证法,假设K不在此范围内(2<=K<=sqrt(N))

因为它是一个合数,所以在(2~N-1)内肯定会有一个数是它的约数(我们假设为M),又因为这个数不在此范围内(2<=这个数<=sqrt(N)),所以M属于[sqrt(N)+1,N-1]。不妨令 (这可能是高中数学的专用名词) K=N/M ,则肯定在此范围内了(2<=K<=sqrt(N))。
方法:我们只需扫描一下此范围内的数有没有N的约数,如果有则不是素数,反之就是素数。不难知道:时间复杂度为O(sqrt(N))

评价:代码简单,容易理解,比较好写加好像,判断单个数貌似也不慢(好像只有优点的样子) 但要判断N个数的话,恐怕就要JJ了。
代码

 inline bool judge(int n){ if(n==1) return false;//特判1 for(register int i=2;i<=sqrt(n);i++){//扫描的过程 if(n%i==0) return false; } return true; } 
法二:Miller-Rabin素性测试

这个方法其实就是利用了定理三,费马小定理的逆定理,由于费马小定理的逆定理不一定成立,所以我们要多次测试。

方法的可行性: 若N通过一次测试,则N不是素数的概率为(1、4)( 不要问我为什么,因为蒟蒻不懂 ) 若N通过t次测试,则N不是素数的概率为(1/4t),所以测试次数越多越准确。事实上t为5时,N不是素数的概率已经为(1/128),高达99.99%。(如果判断错,原因有二:一:你脸黑,二:故意卡)
方法的失误:假如随机选取四个数为2,3,5,7 ,则在2.5*1013 以内唯一一个判断失误的数为
评价小心脸黑,注意被卡! ,时间复杂度(O(tlog2(n))),貌似也不慢的样子。
代码:

#include<iostream> #include<cstdio> #include<ctime> #include<cstdlib> #define ll long long using namespace std; const ll count=10; int flag; ll quick_pow(ll a,ll u,ll n){//快速幂 ll ans=1; while(u!=0){ if(u%2==1) ans=ans*a%n; a=a*a%n; u=u/2; } return ans; } int main(){ srand(time(NULL));//随机种子 ll n; cin>>n; ll a; if(n==2){//特判2 cout<<"Probably a prime\n"; return 0; } flag=0; for(int i=1;i<=count;i++){//测试 a=rand()%(n-2)+2;//随机性的a if(quick_pow(a,n-1,n)!=1){//判断 flag=1;break; } } if(flag==0) cout<<"Probably a prime\n";//输出 else cout<<"A composite\n"; return 0; } 

三.素数的筛法

(求1~N之内的素数)

法一:暴力判断1(N范围内,每个都用Miller-Rabin素性测试)

评价:这个方法不建议用,即使N范围比较小。

原因一:时间复杂度高,O(N t log2n)

原因二:容错率提高了N倍 (但还是很小很小,也不算是原因吧。)

代码就不放了

法二:暴力判断2(N范围内,每个数都试除法判断)

评价:这个方法若在N范围比较小的情况下,闲的没事写写玩玩吧。

代码:

inline bool judge(int n){ if(n==1) return false; for(register int i=2;i<=sqrt(n);i++){ if(n%i==0) return false; } return true; } //以下主函数里面 for(register int i=1;i<=cnt;i++){ if(judge(i)) printf("YES\n");//判断cnt范围内的i是不是质数 else printf("NO\n"); } 
法三:Eratosthenes 筛选法(埃氏筛法)

基本思想:质数的倍数一定不是素数。

方法:用一个v数组标记此数是不是合数(0表示素数,1表示非素数)。先假设所有的数都是素数(初始化v数组为零),从小到大枚举每一个素数,把x的倍数都标记为非素数(标记为一)。枚举到一个数x,若它尚未被标记,则他不能被2~x-1之间的任意数整除,该数就是素数 (这是定义啊)

注意:在枚举时我们要从二开始枚举。一的情况要特判

代码

void primes(int n){ memset(v,0,sizeof(v));//初始化v数组 v[1]=1;//特判1 for(int i=2;i<=n;i++){ if(v[i]==0) for(int j=i;j<=n/i;j++) v[i*j]=1;//标记倍数 } return; } 

评价:代码简单友好写,速度也很快,埃氏筛法很常用。但个别卡这种筛法的题就没有办法了。

疑问:为什么 j循环要从(i~N/i)

上界 :因为 i的i倍的之前的数已经被其余的标记了,不需要重复标记。例如:3的2倍标记的数,已经被2的3倍给标记了。所以我们只需要标记3的(3~n/3)倍就好。
下界:范围不超过n

时间复杂度接近 O(n),为O(nloglogn)。 是一种常用的筛法。

为什么不是O(n)?

因为此筛法仍然会重复标记合数,例如12既可以被2标记,也可以被3表记。因为12=2×6,12=3×4。其根本原因是算法不能唯一确定12的产生方式。

因此,线性筛法应运而生。

法四:线性筛法

方法:我们在生成一个需要标记的合数时,每次只向现有的数乘上一个质因子(缘于原理一,唯一分解定理),并且让它是这个和数的最小质因子。(避免重复标记) 这相当于让合数的质因子从大到小累积,即让12只以 3×2×2这一种方式产生(为什么不是2×2×3,因为在统计质因子时,先是2后是3,所以6是因为3×2得来,然后枚举到6时,又×2,所以是3×2×2。(这个地方不太好懂,主要是我描述的可能不太清楚,还是看代码吧)

代码

 inline void primes(int n){ for(register int i=2;i<=n;i++){ if(!v[i]){ v[i]=i;//素数的最小质因子是其本身 prime[++m]=i;//记录素数 } for(register int j=1;j<=m;j++){ if(prime[j]>n/i||prime[j]>v[i]) break;//超出范围n或有比prime[j]更小的质因子直接终止(prime[]单调递增) v[i*prime[j]]=prime[j];标记最小质因子 } } for(int i=1;i<=m;i++) printf("%d ",prime[i]);//输出素数 } 

顾名思义,时间复杂度O(n)
每个数只被标记一次,所以是O(n)

算法定理:唯一分解定理

评价:算法速度快,O(n)能不快吗 ,一般不会被卡吧,其实埃氏筛法我也没见到被卡的时候。

素数基本上就这点基础知识,其他的会延伸,或者把一些算法结合起来。

今天的文章
数论篇之素数详解_数学素数分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/60728.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注