菜鸟就要老老实实重新学起:
简单素数判断:
就是暴力判素数,O(sqrt(n))
模版:
bool prime(int a)
{
if(a==0||a==1)return false;
if(a==2)return true;
if(a%2==0)return false;
for(int i=3;i<=sqrt(a);i+=2)
if(a%i==0)return false;
return true;
}
Sieve Prime素数筛选:
就是在枚举质因子排除合数。
首先是基本的筛法,枚举所有素数的倍数:
模版:
#define N 11234567
bool mark[N];
void SP()
{
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false;
for(int i=2;i*i<=N;i++)
if(mark[i])
for(int j=2;j*i<N;j++)
mark[j*i]=false;
}
还有改进的利用最小素因子扫,可以避免重复。
#define N 11234567
bool mark[N];
int pri[N],cnt;
void SP()
{
cnt=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false;
for(int i=2;i<N;i++)
{
if(mark[i])
pri[cnt++]=i;
for (int j=0;(j<cnt)&&(i*pri[j]<N);j++)
{
mark[i*pri[j]]=false;
if (i%pri[j]==0)
break;
}
}
}
Miller-Rabin素数测试:
费马小定理:gcd(a,n)==1,a^(n-1)==1(mod n),n为素数.
Carmichael:满足费小的合数,341,561,1105,1729……1e9范围内255个。
二次探测定理:x^2==1(mod n),n为素数,x==1||x==n-1.
就是直接利用费马小定理进行素数测试再加上二次探测定理判定就可以达到很高的正确率,随机算法,测试次数越多越准确。
模版:
//随机算法判定次数,N越大,判错概率越小
#define N 100
long long mod_exp(long long x,long long k,long long mod)
{
long long ans = 1;
while(k)
{
if(k & 1) ans = ans*x%mod;
x = x*x%mod;
k >>= 1;
}
return ans;
}
bool miller_rabin(long long n)
{
if(n == 2 || n == 3 || n == 5 || n == 7 || n == 11) return true;
if(n == 1 || !(n%2) || !(n%3) || !(n%5) || !(n%7) || !(n%11)) return false;
long long x, pre, u;
int i, j, k = 0;
u = n - 1;
while(!(u&1))
{
k++;
u >>= 1;
}
srand((long long)time(0));
for(i = 0; i < N; ++i)
{
x = rand()%(n-2) + 2;
if((x%n) == 0)
continue;
x = mod_exp(x, u, n);
pre = x;
for(j = 0; j < k; ++j)
{
x = (x*x)%n;
//二次探测判断
if(x == 1 && pre != 1 && pre != n-1)
return false;
pre = x;
}
//费小判断
if(x != 1)
return false;
}
return true;
}