《数论及应用》第2章 素数问题

本文深入讲解素数的各种性质和测试方法,包括素数定理、哥德巴赫猜想、孪生素数猜想等,并介绍了埃拉斯托塞尼筛法、6N+1法等多种高效筛选素数的方法。
部署运行你感兴趣的模型镜像

1.素数


素数定理:   随着x增长,π(x)/ ( x / ln x ) = 1

        推论: pn是第n个素数,pn ~ n / ln n


伯兰特猜想:对于任意给定的正整数n,其中n>1,存在一个素数p,使得n<p<2*n


孪生素数猜想:存在无穷多的形如p和p+2的素数对


哥德巴赫猜想:大于2的正偶数可以表示成两个素数之和


n^2+1猜想:存在无穷多个形如n^2+1的素数


素数分布的应用:(素数定理)

http://acm.nefu.edu.cn/JudgeOnline/problem/117.jsp

这个题的话,书上的代码有些累赘,思路是一样的

求的是10^n以内的素数的个数的位数,先用素数定理求个数,然后对10取对数取整加1

#include <stdio.h>
#include <math.h>
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        double m;
        m=double(n-log10(n)-log10(log(10)));
        n=int(m)+1;
        printf("%d\n",n);
    }
    return 0;
}




http://acm.nefu.edu.cn/JudgeOnline/problem/2.jsp

水题,先素数打表,然后判断

#include <stdio.h>
#include <string.h>
const int N=16777220;
int prime[N];
void Prime(int n)
{
    memset(prime,0,sizeof(prime));
    prime[1]=1;prime[0]=1;
    for(int i=2;i*i<=n;i++)
        if(prime[i]==0)
            for(int j=2*i;j<=n;j+=i)
                prime[j]=1;
}
int main()
{
    int n;
    Prime(N);
    int t;
    while(scanf("%d",&n)!=EOF)
    {
        t=0;
        for(int i=2;i<n/2+1;i++)
            if(!prime[i]&&!prime[n-i])
                t++;
        printf("%d\n",t);
    }
    return 0;
}



2.素数测试

[1]埃拉斯托尼斯筛法:

代码实现:

bool prime[N];
void Prime(int n)
{
    memset(prime,true,sizeof(prime));
    prime[1]=0;prime[0]=0;
    for(int i=2;i*i<=n;i++)
        if(prime[i])
            for(int j=2*i;j<=n;j+=i)
                prime[j]=0;
}



[2]   6N + 1  法 :

内循环是2,外循环是3,筛选次数减少,效率提高

代码实现:

// 6N+1法 筛选次数大大减少,但是感觉一般,效率一般
int prime[max],n=0;
bool isprime(int n)
{
    if(n==2)
        return true;
    if(n%2==0)
        return false;
    for(int i=3;i*i<=n;i+=2)
        if(!(n%i))
            return false;
    return true;
}
void Prime()
{
    for(int i=1;i<=max;i+=3)
        for(int j=0;j<2;j++)
            if(isprime(2*(i+j)-1))
                prime[n++]=2*(i+j)-1;
}




http://acm.hdu.edu.cn/showproblem.php?pid=2098

水题....感觉跟前面那个没什么两样

#include <stdio.h>
#include <string.h>
#define N 10000
bool prime[N];
void Prime(int n)
{
    memset(prime,true,sizeof(prime));
    prime[0]=0;
    prime[1]=0;
    for(int i=2;i*i<=n;i++)
        if(prime[i]==1)
            for(int j=2*i;j<=n;j+=i)
                prime[j]=0;
}
int main()
{
    Prime(N);
    int n;
    while(scanf("%d",&n)!=EOF,n!=0)
    {
        int t=0;
        for(int i=2;i<n/2;i++)
            if(prime[i]&′[n-i])
                t++;
        printf("%d\n",t);
    }
    return 0;
}




http://acm.nefu.edu.cn/JudgeOnline/problem/109.jsp

水题:

#include <stdio.h>
#include <string.h>
#define N 10010
bool prime[N];
void Prime()
{
    memset(prime,1,sizeof(prime));
    prime[0]=prime[1]=0;
    for(int i=2;i*i<=N;i++)
        if(prime[i])
            for(int j=2*i;j<=N;j+=i)
                prime[j]=0;
}
int main()
{
    Prime();
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(prime[n]==1)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}



http://poj.org/problem?id=2689

终于不是水题了.....但是卡住了,尼玛...数量级21亿

分区筛选:

#include <stdio.h>
#include <string.h>
#define maxn 1000005
int prime[maxn];
int cnt[maxn];
int main()
{
    int l,r;
    __int64 i,j;
    while(scanf("%d%d",&l,&r)!=EOF)
    {
        memset(prime,1,sizeof(prime));
        if(l==1)
        l=2;
        for(i=2;i*i<=r;i++)
        {
            j=l/i*i;
            if(j<i*i) j=i*i;
            if(j<l) j+=i;
            for(;j<=r;j+=i)
               prime[j-l]=0;
        }
        int c=0;
        for(i=l;i<=r;i++)
            if(prime[i-l])
                cnt[c++]=i;
        if(c<=1)
        {
            printf("There are no adjacent primes.\n");
            continue;
        }
        int mm=-1,nn=1000000000;
        int sm,sn;
        for(i=1;i<c;i++)
        {
            if(cnt[i]-cnt[i-1]>mm)
            {
                mm=cnt[i]-cnt[i-1];
                sm=i;
            }
            if(cnt[i]-cnt[i-1]<nn)
            {
                nn=cnt[i]-cnt[i-1];
                sn=i;
            }
        }
        printf("%d,%d are closest, %d,%d are most distant.\n",cnt[sn-1],cnt[sn],cnt[sm-1],cnt[sm]);
    }
    return 0;
}

4.算数基本定理


max(gcd(a,b))+min(gcd(a,b))=a+b


n!的素因子分解中素数p的幂为: [n/p]+[n/p^2]+[n/p^3]+……



http://acm.nefu.edu.cn/JudgeOnline/problem/118.jsp

这个题由于是讨论0的数,也就是讨论10的因子的幂,阶乘数中2的幂大于5的幂,所以直接求5的幂是多少就是了

水题

#include <stdio.h>
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        int sum=0,t=5;
        while(n>=t)
        {
            sum+=n/t;
            t*=5;
        }
        printf("%d\n",sum);
    }
    return 0;
}



http://acm.nefu.edu.cn/JudgeOnline/problem/119.jsp

水题

好吧  我是看了公式的  不然不敢说水

C(2n,n)恰好被p整除的次数由该公式表示:

([ 2n / p ] - 2 [ n / p ] )+ (  [ 2n /  p ^ 2  ] -  2 [ n / p ^ 2 ]  )  +  ……   +    (  [ 2n / p ^ t ] - 2 [ n / p ^ t ]   )

其中 t =  [ log p ( 2n ) ]  

  

#include <stdio.h>
#include <math.h>
int main()
{
    int T,n,p;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&p);
        double t=(log10(2.0*n)/log10(p));
        int sum=0;
        int tag=1;
        for(int i=1;i<=t;i++)
        {
            tag*=p;
            sum+=(int)(2*n/tag)-2*(int)(n/tag);
        }
        printf("%d\n",sum);
    }
    return 0;
}


4.梅森素数


http://imgsrc.baidu.com/forum/pic/item/a5c27d1ed21b0ef416056af8ddc451da80cb3ea2.jpg

n是素数,Mn= 2 ^ n - 1 称为第n个梅森数,可以是素数,也可以是合数

p是素数,Mp= 2 ^ p - 1 也是素数,Mp是梅森素数


梅森素数的判定:

(1) Lucas-Lehmer 判定法:电脑不好敲,还是给个链接吧 http://mathworld.wolfram.com/Lucas-LehmerTest.html 

(2) Miller 素数测试法 : 不是人做的东西,主要思想:费马小定理

费马小定理:假如p是质数,且(a,p)=1,那么 a^(p-1) ≡1(mod p) 假如p是质数,且a,p互质,那么 a的(p-1)次方除以p的余数恒等于1


http://acm.nefu.edu.cn/JudgeOnline/problem/120.jsp

先看下关于  Lucas—Lehmer的一些证明,了解一下这个检测法
http://www.cqvip.com/Read/Read.aspx?id=20141190

这个题用筛法应该是过不了的,所以看看新方法

//这个代码有点问题
//我已经跟书的作者联系了
//以后再过来改吧,看懂的通知可以吱一声

#include <stdio.h>
#include <iostream>
#include <cstdlib>
using namespace std;
long long multi(long long a,long long b,long long m)
{
    long long ret=0;
    while(b>0)
    {
        if(b&1)
            ret=(ret+a)%m;
        b>>1;
        a=(a<<1)%m;
    }
    return ret;
}
int main()
{
    long long sum=1,data[66],tmp;
    int n,p;
    data[1]=4;
    cin>>n;
    while(n--)
    {
        sum=1;
        cin>>p;
        sum<<p;
        sum-=1;
        printf("%lld\n",sum);
        for(int i=2;i<=p-1;i++)
        {
            tmp=multi(data[i-1],data[i-1],sum);
            data[i]=(tmp-2)%sum;
        }
        if(p==2)
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }
    return 0;
}

然后书上陈列了一个貌似又是错的代码,反正不简单,但是是一种必须掌握的素数测试算法,暂时先放放,有时间再回来看看

有谁闲得跑去AC了记得把把代码附上注释发我咯...


这章书上就写了这么多了.....然后我在网上看到了些比较好的资料,分享下:

 主要是素数筛法    http://wenku.baidu.com/view/ab5139697e21af45b307a812.html

 讲了fermat定理,素数判断等 http://wenku.baidu.com/view/4a1f5cfc910ef12d2af9e7a5.html###  (强烈推荐)

 关于梅森素数,我觉得这个总结得很好  http://blog.youkuaiyun.com/pinkcc/article/details/1393144

其中求梅森素数的代码

#include <iostream>
#include <cmath>
using namespace std;
__int64 prime[1000];
bool Int64_cout( __int64 lgint )     //带符号64位整数输出
{
    char temp[24];
    int j=0;
    if(lgint<0)
    {
        cout<<'-';
        lgint=-lgint;
    }
    else if(lgint==0)
    {
        cout<<'0';
        return false;
    }
    while(lgint!=0)
    {
        temp[j++]='0'+lgint%10;
        lgint/=10;
    }
    while(--j>=0)
        cout<<temp[j];
    return true;
}
bool MCN(int mersenneCN)
{
    __int64 ans=1,j,temp,t2,t3;
    int i,k=0,l;
    double st,temp2;
    for(i=0;i<mersenneCN;i++)
        ans*=2;
    ans--;
    //Int64_cout(ans);
    //cout<<endl;
    temp=ans;
    temp2=temp;
    st=sqrt(temp2);
    for(j=1;temp>1;j++)
    {
        t2=6*j-1;
        t3=6*j+1;
        if(temp%t2==0)
        {
            prime[k++]=t2;
            temp/=t2;
            temp2=temp;
            st=sqrt(temp2);
            //Int64_cout(prime[k-1]);
            //cout<<endl;
        }
        if(temp%t3==0)
        {
            prime[k++]=t3;
            temp/=t3;
            temp2=temp;
            st=sqrt(temp2);
            //Int64_cout(prime[k-1]);
            //cout<<endl;
        }
        if(st<=t2)
        {
            prime[k++]=temp;
            break;
        }
    }
    for(l=0;l<(k-1);l++)
    {
        Int64_cout(prime[l]);
        cout<<" * ";
    }
    Int64_cout(prime[l]);
    cout<<" = ";
    Int64_cout(ans);
    cout<<" = ( 2 ^ "<<mersenneCN<<" ) - 1"<<endl;
    return true;
    }
int main()
{
    int MaxN;
    cin>>MaxN;
    int mersenneCN[9]={11,23,29,37,41,43,47,53,59};
    int i;
    for(i=0;i<9;i++)
    {
        if(mersenneCN[i]<=MaxN)
        {
            MCN(mersenneCN[i]);
        }
        else
        break;
    }
    return 0;
}


您可能感兴趣的与本文相关的镜像

Dify

Dify

AI应用
Agent编排

Dify 是一款开源的大语言模型(LLM)应用开发平台,它结合了 后端即服务(Backend as a Service) 和LLMOps 的理念,让开发者能快速、高效地构建和部署生产级的生成式AI应用。 它提供了包含模型兼容支持、Prompt 编排界面、RAG 引擎、Agent 框架、工作流编排等核心技术栈,并且提供了易用的界面和API,让技术和非技术人员都能参与到AI应用的开发过程中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值