zoukankan      html  css  js  c++  java
  • Miiler-Robin素数测试与Pollard-Rho大数分解法

    板题

    Miiler-Robin素数测试

    目前已知分解质因数以及检测质数确定性方法就只能(sqrt{n})试除
    但是我们可以基于大量测试的随机算法而有大把握说明一个数是质数
    Miler-Robin素数测试基于以下两个原理:

    费马小定理

    即我们耳熟能详的
    对于质数(p)

    [a^{p - 1} equiv 1 pmod p ]

    二次探测原理

    对于质数(p),如果存在(x)满足

    [x^2 equiv 1 pmod p ]

    那么(x)只能是(1)或者(p - 1)

    由此我们便可以随机生成多个(x),逐一用以上两个原理检验即可
    只要全都符合,我们就有大概(1 - (frac{1}{4})^{T})的把握说(p)是一个质数
    具体操作时,令(p = 2^{t}r + 1),我们对于(z = 2^{m}r),其中(m)小于等于(t),都使用二次探测原理检验
    最后再利用费马小定理检验

    bool Miller_Rabin(LL n){
    	if (n == 2 || n == 3 || n == 5 || n == 7 || n == 11 || n == 13) return true;
    	if (n == 1 || n % 2 == 0 || n % 3 == 0 || n % 7 == 0 || n % 11 == 0 || n % 13 == 0) return false;
    	int T = 50;
    	LL t = n - 1,k = 0;
    	while (!(t & 1)) t >>= 1,k++;
    	while (T--){
    		LL x = qpow(random(n),t,n),y;
    		REP(i,k){
    			y = x,x = mul(x,x,n);
    			if (x == 1 && y != 1 && y != n - 1) return false;
    		}
    		if (x != 1) return false;
    	}
    	return true;
    }
    

    Pollard-Rho大数分解法

    我们利用式子(x^2 + c)伪随机生成两个数(a)(b),判断(d = (a - b,n))是否大于(1)小于(n),如果是,我们便找打了一个(n)的因子(d),递归处理(frac{n}{d})(d)即可,当我们使用以上的素数判定判定出(n)是质数时,计入答案
    当然我们伪随机生成的两个数可能成环而导致死循环,我们用(Floyd)的大步小步法判环即可
    具体看代码

    LL pr[maxn],pi;
    LL gcd(LL a,LL b){return b ? gcd(b,a % b) : a;}
    LL Pollard_Rho(LL n){
    	LL x = random(n),y = x,c = random(n),step = 1,t = 2;
    	while (true){
    		step++; x = (mul(x,x,n) + c) % n;
    		if (y == x) return 1;
    		LL d = gcd((y - x + n) % n,n);
    		if (d > 1) return d;
    		if (step == t) y = x,t <<= 1;
    	}
    }
    void Find(LL n){
    	if (n == 1) return;
    	if (Miller_Rabin(n)) {pr[++pi] = n; return;}
    	LL p = n; while (p == n) p = Pollard_Rho(n);
    	Find(n / p); Find(p);
    }
    

    至此我们就可以写出POJ1811

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 100005,maxm = 100005;
    const LL INF = 1000000000ll * 1000000000ll;
    inline LL read(){
    	LL out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    inline LL random(LL x){
    	LL re = 0;
    	REP(i,4) re = (re << 14) + rand();
    	return re % x;
    }
    inline LL mul(LL a,LL b,LL P){
    	LL re = 0;
    	for (; b; b >>= 1,a = (a + a) % P)
    		if (b & 1) re = (re + a) % P;
    	return re;
    }
    inline LL qpow(LL a,LL b,LL P){
    	LL re = 1;
    	for (; b; b >>= 1,a = mul(a,a,P))
    		if (b & 1) re = mul(re,a,P);
    	return re;
    }
    bool Miller_Rabin(LL n){
    	if (n == 2 || n == 3 || n == 5 || n == 7 || n == 11 || n == 13) return true;
    	if (n == 1 || n % 2 == 0 || n % 3 == 0 || n % 7 == 0 || n % 11 == 0 || n % 13 == 0) return false;
    	int T = 50;
    	LL t = n - 1,k = 0;
    	while (!(t & 1)) t >>= 1,k++;
    	while (T--){
    		LL x = qpow(random(n),t,n),y;
    		REP(i,k){
    			y = x,x = mul(x,x,n);
    			if (x == 1 && y != 1 && y != n - 1) return false;
    		}
    		if (x != 1) return false;
    	}
    	return true;
    }
    LL pr[maxn],pi;
    LL gcd(LL a,LL b){return b ? gcd(b,a % b) : a;}
    LL Pollard_Rho(LL n){
    	LL x = random(n),y = x,c = random(n),step = 1,t = 2;
    	while (true){
    		step++; x = (mul(x,x,n) + c) % n;
    		if (y == x) return 1;
    		LL d = gcd((y - x + n) % n,n);
    		if (d > 1) return d;
    		if (step == t) y = x,t <<= 1;
    	}
    }
    void Find(LL n){
    	if (n == 1) return;
    	if (Miller_Rabin(n)) {pr[++pi] = n; return;}
    	LL p = n; while (p == n) p = Pollard_Rho(n);
    	Find(n / p); Find(p);
    }
    int main(){
    	//srand(998244353);
    	int T = read(); LL n;
    	while (T--){
    		if (Miller_Rabin(n = read())) puts("Prime");
    		else {
    			pi = 0; Find(n);
    			//REP(i,pi) printf("%lld ",pr[i]); puts("");
    			if (pi == 1) {puts("Prime"); continue;}
    			LL x = pr[1];
    			for (int i = 2; i <= pi; i++)
    				x = min(x,pr[i]);
    			printf("%lld
    ",x);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Java学习笔记-Lambda表达式
    Java学习笔记-枚举类
    Java学习笔记-枚举类
    Java学习笔记-包装类
    js 递归 汉诺塔的例子
    js 用 hasOwnProperty() 判定属性是来自该对象成员,还是原型链
    正则,js函数math()提取混乱字符串中多个字符串内容
    封装好的cookie的三个常用函数 cookie的添加、删除、提取操作函数
    解决ie6下png背景不能透明bug
    ie6下标签定义的高失效,显示的高不受设定的height值影响
  • 原文地址:https://www.cnblogs.com/Mychael/p/9231004.html
Copyright © 2011-2022 走看看