Miller Rabin 随机性素数测试[模板]
http://poj.org/problem?id=1811
View Code
/*=====================================================*\ | Miller Rabin 判断一个大数是不是素数 | Pollard 找出因子 \*=====================================================*/ #define inf 0x3f3f3f3f #define linf inf*inf #define SS 8//Miller测试次数 #define C 240 typedef long long ll; ll N,ans; void swap(ll&x,ll&y) {x=x^y;y=x^y;x=x^y;} ll f_abs(ll x) {return (x)>(0)?(x):(-x);} ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;} ll mul_mod(ll x,ll y,ll z) { //x*y%z ll res=0; x%=z; while(y) { if(y&1) { res+=x; if(res>=z) res-=z; } x<<=1; y>>=1; if(x>=z) x-=z; } return res; } ll exp_mod(ll x,ll y,ll z) { //(x^y)%z ll res=1; while(y) { if(y&1) res=mul_mod(res,x,z); x=mul_mod(x,x,z); y>>=1; } return res; } bool Wintess(ll a,ll n) { //以x为基对n进行Miller测试并实现二次探测 ll m=n-1,x,y,i,j=0; while(m%2==0) { m>>=1,j++; } x=exp_mod(a,m,n); for(i=1;i<=j;i++) { y=exp_mod(x,2,n); if((y==1) && (x!=1) && (x!=n-1)) return true; x=y; } if(y!=1) return true; else return false; } bool mill_rabin(ll s,ll n) { //对n进行s次的Miller测试 ll a, i; if(n==1) return false; if(n==2) return true; if(n%2==0) return false; srand(time(NULL)); for(i=0;i<s;i++) { a=rand()%(n-1)+1; if(Wintess(a,n)) return false; } return true; } ll Pollard(ll n,ll c) { //对n进行因字分解,找出n的一个因子,注意该因子不一定是最小的 ll i,j,k,x,y,d; srand(time(NULL)); i=1, k=2, x=rand()%n, y=x; while(1) { i++; x=(mul_mod(x,x,n)+c)%n; d=gcd(f_abs(y-x),n); if(d>1 && d<n) return d; if(y==x) return n; //该数已经出现过,直接返回即可 if(i==k) { y=x; k<<=1; } } } void get_small(ll n,ll c) { //找出最小的素数因子 ll m; if(n==1) return; if(mill_rabin(SS,n)) { //判断是否为素数 if(n<ans) ans=n; return; } m=n; while(m==n) m=Pollard(n,c--); //找出n的一个因子 get_small(m,c); get_small(n/m,c); } void get_data() { scanf("%lld",&N); } void solve() { if(mill_rabin(SS,N)) puts("Prime"); else { ans=linf; get_small(N,C); printf("%lld\n",ans); } }