您的位置:首页 > 其它

素数 专题

2015-09-06 23:37 204 查看
素数性质总结:

小于x的素数个数(随着x逐渐增大),与x/lnx近似;

素数测试方法,诶拉托色尼筛法:如果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的自然数有可能是素数(代码后面贴上)

n!的素因子分解中的素数p的幂为  n/p+n/p2+n/p3+......

梅森素数:如果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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: