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);
    }
}
posted @ 2013-05-07 22:43  zhang1107  阅读(183)  评论(0编辑  收藏  举报