素数总结
来源:互联网 发布:中级数据库工程师真题 编辑:程序博客网 时间:2024/06/01 07:30
素数定义:素数就是大于1的正整数,并且只能被自己和1整除的数,与之相对应的就是合数;
素数与合数性质:
(1)a>1是合数,当且仅当a=bc,其中1<b<a,1<c<a
(2)合数必有素数因子
(3)如果d>1,,p是素数,并且d|p,则p=d
(4)p是素数且p|ab,那么必有p|a或者p|b
(5)每个大于1的正整数都有一个素因子
素数定理:
随着x的增长,f(x)/(x/lnx)=1;其中f(x)表示小于x的素数个数
推论:令Pn是第n个素数,其中n为正整数,那么Pn~nln n
素数定理常用来大概的判断素数的分布问题
素数判定:
(1)直接暴力
思想:从2开始枚举,直到sqrt(n),只要里面又一个数能被n整除,那么就说明这个数不是素数,反之,如果所有的数都不能被整除,那就说明n是一个素数
int is_prime(int n) { for(int i=2;i<=sqrt(n);i++) { if(n%i==0) return 0; } return 1; }
(2)筛选法
思想:要求10000以内的所有素数,把1-10000这些数都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有幸存的数的倍数都被坏掉为止。 要找出10000以为的所有的素数,则需要一个大小为10000的数组,将其所有元素设置为未标记 首先把1设置为标记,从2开始,标记所有是它倍数的数,然后对下一个没有标记的数进行标记它的倍数。 当标记完成后,所有未标记的数即为素数。
代码:
bool isprime[maxn];//标记 int prime[maxn];//记录素数 int numprime;//计录素数的个数 void doprime()//埃拉托斯尼斯素数筛选法 { numprime=0; memset(isprime,true,sizeof(isprime)); isprime[1]=false; for(int i=2; i<maxn; i++) { if(isprime[i]) { prime[++numprime]=i; for(int j=i*i; j<maxn; j+=i) isprime[j]=false; } } }
当然也可以不打表通过筛选法来判断一个数是不是素数,思想和上面是一样的
bool isprime(int n){ if(n==1)return false; if(n==2)return true; if((n&1)==0)return false; for(int i=3; i*i<=n; i+=2) if(n%i==0) { return false; break; } return true;}
素数判定的应用:http://poj.org/problem?id=2689
代码:http://hi.baidu.com/tianzhang0000/item/b985ebf08e3b0843c9f33792
Miller-rabin测试
/******************************************
费马小定理:假如p是素数,并且(a,p)=1那么a^(p-1)=1(mod p);
威尔逊定理:如果p是素数,(p-1)!=-1(mod p)
费马小定理推论:假如p是素数,且a是正整数,那么a^p=a(mod p);
设n是一个正整数,欧拉函数f(n)定义为不超过n且与n互素的正整数的个数
欧拉定理:设m是一正整数,a是一个整数且(a,m)=1,那么a^f(m)=1(mod m)
miller rabin测试原理:费马小定理
伪素数:a是一正整数,如n是合数且满足a^n=a(mod n),那么n称为以a为基的伪素数
如果存在n不满足a^n=a(mod n),那么n就一定不是素数,当然如果n满足了也不一定是素数
卡迈克尔数:一个合数n,对所以满足(b,n)=1的正整数都有b^(n-1)=1(mod n)。
因此,我们在利用费马小定理来判断素数时,要排除掉卡迈克尔数
二次探测定理:如果p是一个素数,且0<x<p,则方程x^2%p=1的解为x=1或者x=p-1
那么可以根据二次探测定理,在利用费马小定理计算b^n-1%n的过程中增加对整数n的二次探测,一旦发现违背二次探测定理的,就不是素数
******************************************/
#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<ctime>#include<cstdlib>#define N 5 //测试试验次数using namespace std;long long random(long long n)//产生一个随机数{ return (long long)((double)rand()/RAND_MAX*n+0.5);}long long multi(long long a,long long b,long long n)//计算a*b%n---二分的思想,用加法来模拟乘法,避免溢出{ long long ans=0; while(b) { if(b&1) { ans=(ans+a)%n; } b>>=1; a=(a+a)%n; } return ans;}long long quick_mod(long long a,long long b,long long m)//计算a^b%n{ long long ans=1; while(b) { if(b&1) { ans=multi(ans,a,m); b--; } b>>=1; a=multi(a,a,m); } return ans;}bool witness(long long a,long long n)//二次探测定理的实现{ long long m=n-1; int j=0; while(!(m&1)) { j++; m=m/2; } long long x=quick_mod(a,m,n); if(x==1||x==n-1) return false; while(j--) { x=x*x%n; if(x==n-1) return false; } return true;}bool miller_rabin(long long n)//miller rabin算法{ if(n<2)return false; if(n==2)return true; if(n%2==0)return false; for(int i=1; i<=N; i++) { long long a=random(n-2)+1; if(witness(a,n))return false; } return true;}int main(){ int t,n; srand(time(NULL)); cin>>t; while(t--) { cin>>n; if(n==1)break; if(miller_rabin(n))cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 520;}
应用:http://poj.org/problem?id=1811
代码:http://hi.baidu.com/tianzhang0000/item/ee7b00985c7147a583d295b0
另一个应用就是判定梅森素数
欧拉函数
设n是一个正整数,欧拉函数f(n)定义为不超过n且与n互素的正整数的个数
欧拉函数性质:它在整数n上的值等于对n进行素因子分解后,所有的素数幂上的欧拉函数之积
几个定理:
1、如果p是素数,那么f(p)=p-1;反之,如果p是一个正整数且满足f(p)=p-1,那么p一定是素数
2、设p是一个素数,n是一个正整数,那么f(p^n)=p^n-p^(n-1);
3、设m和n是互素的正整数,那么f(m*n)=f(n)*f(m);
4、设n=(p1^a1)*(p2^a2)……(pk^ak)为正整数n的素数幂分解,那么就有f(n)=n*(1-1/p1)*(1-1/p2)……(1-1/pk)
5、当n为奇数时,有f(n)=f(n*2);
6、设n是一个大于2正整数,那么f(n)为偶数
欧拉定理:设m是一正整数,a是一个整数且(a,m)=1,那么a^f(m)=1(mod m)
求欧拉函数的思想:定理4
直接实现:
int euler(int n){ int ans=n; for(int i=2;i<=sqrt(n*1.0);i++) { if(n%i==0) { ans=ans-ans/i; do n=n/i; while(n%i==0) } } if(n>1)//当n素数时,定理1 ans=ans-ans/n; return ans;}
素数表实现
int euler(int n)//素数打表在这儿就不重复{ int ans=n; for(int i=0;prime[i]<=sqrt(n*1.0);i++) { if(n%prime[i]==0) { ans=ans-ans/prime[i]; do n=n/prime[i]; while(n%prime[i]==0) } } if(n>1)//当n素数时,定理1 ans=ans-ans/n; return ans;}
递推求欧拉函数
可以先设所有数的欧拉函数值为自己本身,有定理1可知,如果p是一个正整数且满足f(p)=p-1,那么这个数p就是素数,
在遍历过程中如果玉带欧拉函数与自身相等的情况,那么说明该数为素数,把这个数的欧拉函数值改变,同时也把能被这个数整除的数改变
void euler(){ for(int i=1;i<=maxn;i++)e[i]=i; for(int i=2;i<=maxn;i+=2)e[i]/=2; for(int i=3;i<=maxn;i+=2) { if(e[i]==i) { for(int j=i;j<maxn;j+=i) e[j]=e[j]/i*(i-1); } }}
应用:hdu1659
- 素数总结
- 素数总结
- 素数总结
- 关于素数总结:
- 【转】素数总结
- 找素数算法总结
- 总结--素数(1)
- 筛素数总结
- 7.24 素数总结
- 素数各种方法总结
- 素数判定总结
- 关于素数问题总结
- 反素数的总结
- 素数算法总结
- 素数筛选--总结
- 素数表学习总结
- 反素数总结
- 总结-筛素数
- MSMQ 跨服务器读写队列的“消息队列系统的访问被拒绝”的解决方案
- Eclipse中修改Tomcat的发布路径、发布方式、启动超时等信息
- 栈的顺序实现和链接实现
- IOS简单识记
- c++ builder 如何为application 增加热键(快捷键)
- 素数总结
- SQL Server 2008 重启电脑失败
- §2 回归系数的最小二乘估计
- cocos2d-x的场景
- 安装sql server 2008 报错“检查 Microsoft Visual Studio 2008 的早期版本”失败的问题解
- 学习设计模式六大设计原则之二
- Android中sharedPreferences的用法
- 开源NAC系统PacketFence的安装配置
- §3 回归方程及回归系数的显著性检验