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
原文地址:https://www.cnblogs.com/cautx/p/11385849.html