START
判断一个数是不是素数可以直接暴力或者是素数筛。
但是对于一个特别大的数,直接用素数筛也有可能TLE。
这个时候就要想点别的办法:
1.
筛选法+试除法
首先用素数筛筛出[2,sqrt(n)+1]的素数,然后用这些素数来判断能不能整除n,如果可以,那么n一定是合数,如果都不行,那么n是素数。
void olas()//欧拉筛
{
int i,j;
num=1;
memset(u,true,sizeof(u));
for(int i=2;i<=1000000;i++)
{
if(u[i]) su[num++]=i;
for(int j=1;j<num;j++)
{
if(i*su[j]>1000000) break;
u[i*su[j]]=false;
if(i%su[j]==0) break;
}
}
}
这里使用的是欧拉筛。
筛出素数后一个for循环结束。
2.Miller_Rabin方法
和费马小定理有关的方法。
费马小定理:a^(p-1)=1 (mod p)。a,p互质。
如果a,p互质,那么一定有费马小定理成立,但是反之未必!
但是如果有非常多个a,都和我们要判定的p满足费马小定理,那么我们认为这个p很有可能是素数或者伪素数。
我们把可以满足上式的但却不是质数的p称为伪素数。
既然a取足够多就可以侧面反映p大概率是素数,那么我们就枚举足够多有代表性的a来验算。
现在来证明这个方法的有效性:
如果a^2=1(mod n),则必有a=1 (mod n)或a=n-1 (mod n) .
现在,如果有一个大于2的质数n,令n-1=2^s * d 其中d为奇数。根据费马小定理,如果a不能被n整除,则a^(n-1)%n=1。
由以上性质可以推出a^d =1(mod n),或者a^2 =1 (mod n),a^(2^r *d) =1 (mod n) ,(0<=r<s)其中a为任意自然数。
现在只要找到一个a使得a^d != 1(mod n)或者 a^(2^r * d) != 1 (mod n)就可以说明n不是素数。
Miller_Rabin是一个随机化算法,通过反复验证,得出的结论是,如果任一个数p,通过了以2,7,61为底的Miller_Rabin测试,那么它一定是素数,反之不是素数。
typedef long long ll;
ll qpow(ll a,ll b,ll M)
{
ll ans=1;
while(b)
{
if(b&1) ans*=a,ans%=M;
a*=a;a%=M;b>>=1;
}
return ans;
}
bool Miller_Rabin_Test(ll x,ll n)//n是待测质数
{
ll y=n-1;
while(!(y&1)) y>>=1;
x=qpow(x,y,n);
while(y<n-1&&x!=1&&x!=n-1)
{
x=(x*x)%n;
y<<=(ll)1;
}
return x==n-1||y&1==1;
}
bool solve(ll n)
{
if(n==2||n==7||n==61) return 1;
if(n==1||(n&1)==0) return 0;
return Miller_Rabin_Test(2,n)&&Miller_Rabin_Test(7,n)&&Miller_Rabin_Test(61,n);
}
END