http://acm.hdu.edu.cn/showproblem.php?pid=2138
题意:给n个数判断有几个素数。(每个数<=2^32)
#include <cstdio> using namespace std; typedef long long ll; ll ipow(ll a, ll b, ll m) { ll x=1; for(; b; b>>=1, (a*=a)%=m) if(b&1) (x*=a)%=m; return x; } ll rand(ll a, ll b) { static const ll M=1e9+7, g=154865266; static ll now=1283901ll; return a+((now*=g)%=M)%(b-a+1); } bool check(ll x) { if(x==2 || x==3 || x==5 || x==7 || x==11 || x==13) return 1; if(x<2 || (x&1)==0 || (x%3)==0 || (x%5)==0 || (x%7)==0 || (x%11)==0 || (x%13)==0) return 0; int cnt=0; ll d=x-1; while((d&1)==0) d>>=1, ++cnt; for(int T=1; T<=50; ++T) { int a=rand(2, x-1); ll t=ipow(a, d, x), pre; for(int i=1; i<=cnt; ++i) { pre=t; (t*=t)%=x; if(t==1 && pre!=1 && pre!=x-1) return 0; } if(t!=1) return 0; } return 1; } int main() { int n; while(~scanf("%d", &n)) { int ans=0; for(int i=1; i<=n; ++i) { int a; scanf("%d", &a); if(check(a)) ++ans; } printf("%d ", ans); } return 0; }
学习了素数检测= =Miller-Rabin...复杂度$O(k log^3 n)$,k是选的$a$的个数
其实基于两个定理:费马小定理和二次探测...
首先如果$n$是奇素数,那么显然对于所有的$1 le a < n$,都有$a^{(n-1)} equiv 1 pmod{n}$,那么我们马上可以得到一个暴力算法= =(比枚举约数还慢系列= =
然后用那啥二次探测定理然后随机选一些$a$然后一定概率来检测$n$= =(听说单次检测是$3/4$的概率= =那么多次检测成功率很高= =$n$次的能检测出来的概率就是$1 - left( frac{1}{4} ight) ^n$
二项探测就是指如果$n$是素数,则$x^2 equiv 1 pmod{n}, 0<=x<n$的只有就是$x = 1 或 x = n-1$
证明:容易得到$p | (x+1)(x-1)$。而由于$p$是质数,所以$(x+1)$和$(x-1)$中至少一个被$p$整除。那么容易得到$x = pm 1$,即$x equiv 1 或 x equiv n-1$
然后我们就将$n-1$分解成$2^sd$其中$d$为奇数。这样我们从$a^d$开始向上算,每一次平方一次,如果等于$1$而上一次却不等于$pm 1$,那么为合数。