素数性质总结:

  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\n",a)
#define ptlld(a) printf("%I64d\n",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\n");
            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\n",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\n",a)
#define ptlld(a) printf("%I64d\n",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.\n"); 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.\n",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\n",a)
#define ptlld(a) printf("%I64d\n",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\n",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 \n",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  \n",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\n");
            continue;
        }
        solve();
    }
    return 0;
}

 对素数定理的一些运用:

题目链接:hdu 5778 abs

官方题解:由于y质因数分解式中每个质因数均出现2次,那么y是一个完全平方数,设y=z*z,题目可转换成求z,使得每个质因数出现1次. 我们可以暴力枚举z,检查z是否符合要求,显然当z是质数是符合要求,由素数定理可以得,z的枚举量在logn级别 复杂度 O(\sqrt[4]{n}log\sqrt[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\n",a)
#define ptlld(a) printf("%I64d\n",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\n",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\n",ans);
    }
}
View Code

 

posted on 2015-09-06 23:37  中子星  阅读(534)  评论(0)    收藏  举报