zoukankan      html  css  js  c++  java
  • 素数 专题

    素数性质总结:

    1. 小于x的素数个数(随着x逐渐增大),与x/lnx近似;
    2. 素数测试方法,诶拉托色尼筛法:如果n是一个合数,那么n一定有一个不超过sqrt(n)的素因子;6N±1法:对于任何一个自然数,都可以表示为如下形式之一:6N,6N+1,6N+2,6N+3,6N+4,6N+5(N=0,1,2,3...)显然,当N>=1时,只有形如6N+1,6N+5的自然数有可能是素数(代码后面贴上)
    3. n!的素因子分解中的素数p的幂为  n/p+n/p2+n/p3+......
    4. 梅森素数:如果m是一个正整数,且2m-1是一个素数,则m必是素数(通过2m-1来判断m是否为素数,很重要的运用);如果m是一个正整数,且m是一个素数,则Mm=2m-1称作第m个梅森数,如果p是一个素数,且Mp=2p-1也是素数,则Mp就称为梅森素数。判断方法有lucas-lehmer判定法【设p是素数,第p个梅森素数为Mp=2p-1,r1=4,对于k>=2,利用rk=r2k-1-2(modMp),0<=rk<Mp,可以得到rk序列,则有Mp为素数,当且仅当rp-1=0(modMp).】和miller素数测试法

    miller素数测试法:

    一.费马小定理

    如果n是素数,且gcd(a,n)==1,那么a(n-1)==1(mod n);

    费马小定理只是个必要条件,符合费马小定理而非素数的数叫做Carmichael.

    前3个Carmichael数是561,1105,1729。

    Carmichael数是非常少的。

    在1~100000000范围内的整数中,只有255个Carmichael数。

    为此又有二次探测定理,以确保该数为素数:

    二.二次探测定理

    二次探测定理:如果p是一个素数,0<x<p,则方程x2≡1(mod p)的解为x=1,p-1

    大神orz

    题目集合:

    hdu 2098 分拆素数和  http://acm.hdu.edu.cn/showproblem.php?pid=2098

    6N±1法运用:

    /**************************************************************
        Problem:hdu 2098
        User: youmi
        Language: C++
        Result: Accepted
        Time:0MS
        Memory:1648K
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <deque>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define scs(a) scanf("%s",a)
    #define sclld(a) scanf("%I64d",&a)
    #define pt(a) printf("%d
    ",a)
    #define ptlld(a) printf("%I64d
    ",a)
    #define rep0(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define rep_1(i,n) for(int i=n;i>=1;i--)
    #define rep_0(i,n) for(int i=n-1;i>=0;i--)
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define lson (step<<1)
    #define rson (lson+1)
    #define esp 1e-6
    #define oo 0x3fffffff
    #define TEST cout<<"*************************"<<endl
    
    using namespace std;
    typedef long long ll;
    
    int n;
    
    const int maxn=10000+10;
    int prime[maxn<<2];
    bool isprime(int s)//判断s是否为素数
    {
        if(s%2==0)
            return false;
        for(int i=3;i*i<=s;i+=2)
            if(!(s%i))
            return false;
        return true;
    }
    void prim()
    {
        prime[2]=prime[3]=1;
        for(int i=3;i<maxn;i+=3)
        {
            for(int j=0;j<2;j++)
            {
                if(isprime(2*(i+j)-1))//当j=0时为6N-1,当j=1时为6N+1。
                    prime[2*(i+j)-1]=1;
            }
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        prim();
        while(~sc(n))
        {
            if(n==0)
                break;
            if(n<=4)
            {
                printf("0
    ");
                continue;
            }
            int ans=(prime[n-2]&&prime[2]);
            for(int i=3;i<n-i;i+=2)
            {
                if(prime[i]&&prime[n-i])
                    ans++;
            }
            pt(ans);
        }
        return 0;
    }

    诶拉托色尼筛法:

    #include <iostream>
    #include <stdio.h>
    //46Ms   244k
    using namespace std;
    const int maxn=10000+10;
    bool prim[maxn];
    int num[maxn];
    int pnt,n,cnt;
    void prime()
    {
        num[0]=2;
        pnt=1;
        for(int i=3;i<=10000;i+=2)
        {
            if(!prim[i])
            {
                num[pnt++]=i;
                for(int j=i*i;j<=10000;j=j+(i*2))
                {
                    prim[j]=true;
                }
            }
        }
        pnt--;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        prime();
        while(scanf("%d",&n)==1&&n)
        {
            int p=1;
            cnt=0;
            for(int i=num[p];i<n/2;i=num[++p])
            {
                int remainder=n-i;
                int pos=p;
                if(remainder%2!=0)
                {
                    for(int k=i;k<=n&&pos<=pnt;k=num[++pos])
                    {
                        if(remainder==k)
                        {
                            cnt++;
                            break;
                        }
                    }
                }
            }
            printf("%d
    ",cnt);
        }
        return 0;
    }

    poj 2689 Prime Distance   http://poj.org/problem?id=2689 诶拉托色尼筛法的经典题目,两次都是运用这个原理来筛选。第一次把(1<<16)以内的素数全都筛出来,因为R-L<=1000000,所以可以通过(1<<16)以内的素数来筛选L-R之间的素数,而且可以保存在一个大小为1000000的数组里(这其中的奥秘看看代码就好了)。  

    /**************************************************************
        Problem:poj 2689
        User: youmi
        Language: C++
        Result: Accepted
        Time:16MS
        Memory:1580K
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <deque>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define scs(a) scanf("%s",a)
    #define sclld(a) scanf("%I64d",&a)
    #define pt(a) printf("%d
    ",a)
    #define ptlld(a) printf("%I64d
    ",a)
    #define rep0(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define rep_1(i,n) for(int i=n;i>=1;i--)
    #define rep_0(i,n) for(int i=n-1;i>=0;i--)
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define lson (step<<1)
    #define rson (lson+1)
    #define esp 1e-6
    #define oo 0x3fffffff
    #define TEST cout<<"*************************"<<endl
    
    using namespace std;
    typedef long long ll;
    
    const int maxn=50010;
    ll prime[maxn];
    bool isprime[maxn*20];
    int tot;
    ll l,r;
    ll ans[maxn*20];
    void prim()
    {
        tot=0;
        memset(isprime,true,sizeof(isprime));
        prime[tot++]=2;
        for(int i=3;i<maxn;i+=2)
        {
            if(isprime[i])
            {
                prime[tot++]=i;
                for(ll j=i;1ll*i*j<1ll*maxn;j+=2)
                    isprime[i*j]=false;
            }
        }
    }
    void work()
    {
        memset(isprime,true,sizeof(isprime));
    //以下为两种对L-R之间的数进行筛选的方法
    /**<for(int i=0;i<tot;i++) { if(prime[i]>r) break; ll temp=l/prime[i]; while(temp*prime[i]<l||temp<=1)//如果temp=1,也就是temp*prime[i]==prime[i],而prime[i]为素数,所以要特判temp==1的情况 temp++; for(ll j=temp*prime[i];j<=r;j+=prime[i]) if(j>=l) isprime[j-l]=false;//因为R-L<=1000000,所以判断j以后,做差j-l就可以把结果放在一个1000000大小的数组里了 } */ for(int i=0;i<tot;i++) { ll a=(l-1)/prime[i]+1;
         if(a==1) a++;//这一步的道理同上 ll b
    =r/prime[i]; for(ll j=a;j<=b;j++) isprime[j*prime[i]-l]=false; } } void solve() { work(); int cnt=0; ll temp=r-l; for(ll i=0;i<=temp;i++) { if(isprime[i]) ans[cnt++]=l+i; } /**<rep0(i,cnt) printf("%lld ",ans[i]); cout<<endl; */ ll mn,mx; ll ansl1,ansl2,ansr1,ansr2; if(cnt<=1) { printf("There are no adjacent primes. "); return ; } ansl1=ansr1=ans[0]; ansl2=ansr2=ans[1]; mn=mx=ans[1]-ans[0]; for(int i=2;i<cnt;i++) { if(mx<ans[i]-ans[i-1]) { mx=ans[i]-ans[i-1]; ansr1=ans[i-1],ansr2=ans[i]; } if(mn>ans[i]-ans[i-1]) { mn=ans[i]-ans[i-1]; ansl1=ans[i-1],ansl2=ans[i]; } } printf("%lld,%lld are closest, %lld,%lld are most distant. ",ansl1,ansl2,ansr1,ansr2); } int main() { //freopen("in.txt","r",stdin); prim(); while(~scanf("%lld%lld",&l,&r)) { if(l==1) l=2;//因为1比较特殊,所以单独拿出来特判掉,要不然很吃亏的 solve(); } return 0; }

    hdu 2138 How many prime numbers  http://acm.hdu.edu.cn/showproblem.php?pid=2138 虽然这题比较水,可以直接判断sqrt(n)以内的数是否可以被n整除来判断n是否为素数。但如果用miller素数测试法来做的话还是挺好的一个训练题。不过坑点也蛮多的,我用g++编译相同的代码就tle,而c++就可以刚好过,具体的代码中有标识

    /**************************************************************
        Problem:hdu 2138
        User: youmi
        Language: C++
        Result: Accepted
        Time:764MS
        Memory:1732K
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <deque>
    #include <ctime>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define scs(a) scanf("%s",a)
    #define sclld(a) scanf("%I64d",&a)
    #define pt(a) printf("%d
    ",a)
    #define ptlld(a) printf("%I64d
    ",a)
    #define rep0(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define rep_1(i,n) for(int i=n;i>=1;i--)
    #define rep_0(i,n) for(int i=n-1;i>=0;i--)
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define lson (step<<1)
    #define rson (lson+1)
    #define esp 1e-6
    #define oo 0x3fffffff
    #define TEST cout<<"*************************"<<endl
    
    using namespace std;
    typedef long long ll;
    int N;
    //下面分别是判15次和判10次的时间差别
    const int Times=15;//998MS    1728K
    //const int Times=10 764MS  1732K
    ll mod_mul(ll a,ll b,ll mod)
    {
        ll res=0;
        a%=mod;
        while(b)
        {
            if(b&1)
                res=(res+a)%mod;
            b>>=1;
            a=(a<<1)%mod;
        }
        return res;
    }
    ll mod_exp(ll a,ll b,ll mod)
    {
        ll res=1;
        a%=mod;
        while(b)
        {
            if(b&1)
                res=mod_mul(res,a,mod);
            b>>=1;
            a=mod_mul(a,a,mod);
        }
        return res;
    }
    bool miller_rabin(ll n)
    {
        if(n==2||n==3||n==5||n==7||n==11)
            return true;
        if(n==1||n%2==0||n%3==0||n%5==0||n%7==0||n%11==0)
            return false;
        int tot=0;
        ll u=n-1; //要求x^u % n
        while(!(u&1))//如果u为偶数则u右移,用tot记录移位数,然后可以利用x^2==1来进行tot次二次判定,
        {
            tot++;u>>=1;
        }
        rep1(i,Times)//进行Times次测试
        {
            ll x=rand()%(n-2)+2;//在[2, n)中取随机数
            if(x==n)
                continue;
            x=mod_exp(x,u,n);//先计算(x^u) % n
            ll pre=x;
            rep0(j,tot)//把移位减掉的量补上,并在这地方加上二次探测
            {
                x=mod_mul(x,x,n);
                if(x==1&&pre!=1&&pre!=n-1)//二次探测定理,这里如果x = 1则pre 必须等于 1,或则 n-1否则可以判断不是素数
                    return false;
                pre=x;
            }
            if(x!=1)//费马小定理
                return false;
        }
        return true;
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(~sc(N))
        {
            ll a;
            int cnt=0;
            srand(time(NULL));//随机数种子生成器
            while(N--)
            {
                sclld(a);
                if(miller_rabin(a))
                    cnt++;
            }
            pt(cnt);
        }
        return 0;
    }

    poj 1777 Vivinan's Problem  http://poj.org/problem?id=1777  梅森素数性质题,cxlove 大神orz

    /**************************************************************
        Problem:poj 1777
        User: youmi
        Language: C++
        Result: Accepted
        Time:297MS
        Memory:176K
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define Max(a,b) (a)>(b)?(a):(b)
    #define Min(a,b) (a)<(b)?(a):(b)
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define rep0(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define rep_0(i,n) for(int i=n-1;i>=0;i--)
    #define rep_1(i,n) for(int i=n;i>=1;i--)
    #define pt(a) printf("%d
    ",a)
    #define lson (step<<1)
    #define rson (lson+1)
    #define esp 1e-6
    #define oo 0x3fffffff
    #define TEST cout<<"*************************"<<endl
    
    using namespace std;
    typedef long long ll;
    int n;
    const int maxn=110;
    int a[maxn];
    int M[8]={3,7,31,127,8191,131071,524287,2147483647};
    int p[8]={2,3,5,7,13,17,19,31};
    int dp[1<<8];
    int work(int temp)
    {
        int res=0;
        for(int i=0;i<8;i++)
        {
            if(temp%M[i]==0)
            {
                temp/=M[i];
                if(temp%M[i]==0)
                    return 0;
                res|=(1<<i);
            }
        }
        if(temp!=1)
            return 0;
        return res;
    }
    int cal()
    {
        zeros(dp);
        int ans=0;
        int res;
         /**< pt(n);
        rep0(i,n)
            printf("%d ",a[i]);
        cout<<endl;*/
        rep0(i,n)
        {
            res=0;
            for(int j=0;j<8;j++)
            {
                if(a[i]&(1<<j))
                    res+=p[j];
            }
            dp[a[i]]=res;
            //printf("%d %d 
    ",a[i],res);
            ans=Max(dp[a[i]],ans);
        }
        return ans;
    }
    void solve()
    {
        int ans=cal();
        int bit=(1<<8)-1;
        for(int i=1;i<=bit;i++)
        {
            for(int j=1;j<=bit;j++)
            {
                if(!(i&j))
                {
                    int temp=i|j;
                    dp[temp]=Max(dp[i]+dp[j],dp[temp]);
                    //printf("dp[%d]=%d  dp[%d]=%d  dp[%d]=%d  
    ",i,dp[i],j,dp[j],temp,dp[temp]);
                    ans=Max(ans,dp[temp]);
                }
            }
        }
        pt(ans);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(~sc(n))
        {
            rep0(i,n)
            {
                sc(a[i]);
                a[i]=work(a[i]);
                if(a[i]==0)
                    i--,n--;
            }
            if(n==0)
            {
                printf("NO
    ");
                continue;
            }
            solve();
        }
        return 0;
    }

     对素数定理的一些运用:

    题目链接:hdu 5778 abs

    官方题解:由于y质因数分解式中每个质因数均出现2次,那么y是一个完全平方数,设y=z*z,题目可转换成求z,使得每个质因数出现1次. 我们可以暴力枚举z,检查z是否符合要求,显然当z是质数是符合要求,由素数定理可以得,z的枚举量在logn级别 复杂度 O(sqrt[4]{n}logsqrt[2]{n}4​​n​​log2​​n​​)

    /**************************************************************
        Problem:hdu 5778 abs
        User: youmi
        Language: C++
        Result: Accepted
        Time:31MS
        Memory:1556K
        solution:由于y质因数分解式中每个质因数均出现2次,那么y是一个完全平方数,设y=z*z,
                 题目可转换成求z,使得每个质因数出现1次. 我们可以暴力枚举z,检查z是否符合
                 要求,显然当z是质数是符合要求,由素数定理可以得,z的枚举量在logn级别
                  复杂度 O(n^(1/4)log(n^(1/2)))
    ****************************************************************/
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#include<bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #include <cmath>
    #include <queue>
    #include <deque>
    #include <string>
    #include <vector>
    #define zeros(a) memset(a,0,sizeof(a))
    #define ones(a) memset(a,-1,sizeof(a))
    #define sc(a) scanf("%d",&a)
    #define sc2(a,b) scanf("%d%d",&a,&b)
    #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define scs(a) scanf("%s",a)
    #define sclld(a) scanf("%I64d",&a)
    #define pt(a) printf("%d
    ",a)
    #define ptlld(a) printf("%I64d
    ",a)
    #define rep(i,from,to) for(int i=from;i<=to;i++)
    #define irep(i,to,from) for(int i=to;i>=from;i--)
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define lson (step<<1)
    #define rson (lson+1)
    #define eps 1e-6
    #define oo ((1ll<<62)-1)
    #define TEST cout<<"*************************"<<endl
    const double pi=4*atan(1.0);
    
    using namespace std;
    typedef long long ll;
    template <class T> inline void read(T &n)
    {
        char c; int flag = 1;
        for (c = getchar(); !(c >= '0' && c <= '9' || c == '-'); c = getchar()); if (c == '-') flag = -1, n = 0; else n = c - '0';
        for (c = getchar(); c >= '0' && c <= '9'; c = getchar()) n = n * 10 + c - '0'; n *= flag;
    }
    int Pow(int base, ll n, int mo)
    {
        if (n == 0) return 1;
        if (n == 1) return base % mo;
        int tmp = Pow(base, n >> 1, mo);
        tmp = (ll)tmp * tmp % mo;
        if (n & 1) tmp = (ll)tmp * base % mo;
        return tmp;
    }
    //***************************
    
    const int maxn=50010;
    ll n;
    bool work(ll x)
    {
        for(ll i=2;i*i<=x;i++)
        {
            if(x%i==0)
            {
                ll temp=x/i;
                if(temp%i==0)
                    return false;
            }
        }
        return true;
    }
    int c[]={0,3,2,1,0,1,2,2,1,0,1};
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        #endif
        int T_T;
        scanf("%d",&T_T);
        for(int kase=1;kase<=T_T;kase++)
        {
            sclld(n);
            if(n<=10)
            {
                printf("%d
    ",c[n]);
                continue;
            }
            ll tt=(ll)sqrt(n*1.0);
            ll ans=oo;
            for(ll i=tt;i>=2;i--)
            {
                if(work(i))
                {
                    ans=Min(ans,abs(n-i*i));
                    break;
                }
            }
            for(ll i=tt+1;i<=n;i++)
            {
                if(work(i))
                {
                    ans=Min(ans,abs(n-i*i));
                    break;
                }
            }
            printf("%I64d
    ",ans);
        }
    }
    View Code
    不为失败找借口,只为成功找方法
  • 相关阅读:
    Guzz入门教程
    设计模式开题
    纪录idea不能创建class类问题(Cannot Create Class)
    dbrouter实现流程图
    记录一次concurrent mode failure问题排查过程以及解决思路
    程序员的自我修养
    CyclicBarrier之共享锁的理解
    sed选项详解(options)
    sed 范围查找
    Sed命令
  • 原文地址:https://www.cnblogs.com/youmi/p/4787734.html
Copyright © 2011-2022 走看看