素数总结

来源:互联网 发布:中级数据库工程师真题 编辑:程序博客网 时间:2024/06/01 07:30

素数定义:素数就是大于1的正整数,并且只能被自己和1整除的数,与之相对应的就是合数;

素数与合数性质:

  (1a>1是合数,当且仅当a=bc,其中1<b<a,1<c<a

   (2)合数必有素数因子

  (3)如果d>1,p是素数,并且d|p,则p=d

  (4p是素数且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、设mn是互素的正整数,那么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




原创粉丝点击