素数总结

素数定义:素数就是大于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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常感谢您的提问,以下是问题的总结: 1. 如何使用C语言循环实现输入10个正整数? 答:可以使用一个循环来输入10个正整数,每次读入一个数字并存储到数组中。 2. 如何判断一个正整数是否为素数? 答:可以使用一个循环来判断一个正整数是否为素数,如果该数可以被2到sqrt(n)之间的任意一个数整除,则该数不是素数。 3. 如何统计输入的10个正整数素数的个数并输出? 答:可以使用一个计数器来统计素数的个数,每次判断一个数字是否为素数时,如果是素数则将计数器加1。最终输出计数器的值即为素数的个数。 下面是解题思路和代码实现: 解题思路: 1. 定义一个数组和一个计数器,用来存储输入的10个正整数和统计素数的个数; 2. 使用一个循环输入10个正整数,并将它们存储到数组中; 3. 使用一个嵌套循环来判断每个数字是否为素数,如果是素数则将计数器加1; 4. 输出素数的个数。 代码实现: ```c #include <stdio.h> #include <math.h> int main() { int nums[10], count = 0; int i, j; for (i = 0; i < 10; i++) { printf("请输入第%d个正整数:", i+1); scanf("%d", &nums[i]); } for (i = 0; i < 10; i++) { int flag = 1; for (j = 2; j <= sqrt(nums[i]); j++) { if (nums[i] % j == 0) { flag = 0; break; } } if (flag && nums[i] != 1) { count++; printf("%d ", nums[i]); } } printf("\n一共有%d个素数\n", count); return 0; } ``` 在上述代码中,我们使用了sqrt函数来计算数字n的平方根,这样可以减少循环的次数,提高程序的效率。同时,我们还特别判断了数字1,因为1既不是素数也不是合数,因此需要特别处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值