POJ1811 Prime Test (Pollard-Rho算法) Sunshine大神

来源:互联网 发布:佳能 cr2 编辑软件 编辑:程序博客网 时间:2024/05/22 13:22

目录(?)[-]

  1. 一类问题 判定一个整数nn1是否为素数
    1. 算法1
    2. 算法2
    3. Miller-Rabin算法

很久没有写博客了。。。最近军训加开学,感觉刷题速度有降低,要补一补。


回归正题,正式进入数论阶段,讨论一下关于素数判定的那些事。

一类问题: 判定一个整数n(n>1)是否为素数。

算法1:

直接根据素数的定义枚举i2(n1),如果n%i==0n为合数。
时间复杂度:O(n)

<code class="language-cpp hljs  has-numbering"><span class="hljs-keyword">bool</span> is_prime(<span class="hljs-keyword">int</span> n) {    <span class="hljs-keyword">int</span> i;    <span class="hljs-keyword">for</span>(i = <span class="hljs-number">2</span>; i < n; i++)        <span class="hljs-keyword">if</span>(n % i == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

算法2:

发现若存在i<n使得n%i==0,则必有n%(n/i)==0
所以只需枚举i2sqrt(n)即可。
时间复杂度:O(n)

<code class="language-cpp hljs  has-numbering"><span class="hljs-keyword">bool</span> is_prime(<span class="hljs-keyword">int</span> n) {    <span class="hljs-keyword">int</span> i;    <span class="hljs-keyword">for</span>(i = <span class="hljs-number">2</span>; i * i <= n; i++)        <span class="hljs-keyword">if</span>(n % i == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

Miller-Rabin算法:

这是一种随机性素数判定算法,也就是说,答案可能出错,但是可能性极小。

先是讲两个定理:

费马小定理:
对于一个质数p,取任意整数a,满足gcd(p,a)=1,则有

ap11(modp)

二次探测定理:
对于0<x<p,若p是素数,则方程:

x21(modp)

的解为:
x1=1,x2=p1

因为费马小定理的逆命题不成立,而否逆命题成立,所以我们可以利用一下一点:
对于任意整数a<p,不满足ap11(modp),则p为合数。

所以我们可以不断在区间[2,p1]范围内随机取a,并进行判定。在s次判定不为合数之后,我们就可以说这个数是质数。

但是这还不够精确,我们可以先把p1分解成2t×u(u{x|x=2k+1,kN})的形式,然后令x[0]=aumodp,,那么将x[0]平方t次就是(au)2tmodp的值,我们设x[i]x[0]平方i次的值,根据二次探测定理,若x[i]等于1,则x[i1]等于1或p-1,不满足则p为合数。

注意以上操作中所有的形如abmodp的式子都要用快速幂运算,当n比较大时,形如a×bmodp的式子也要使用分治的思想来计算。

这就是Miller-Rabin算法的主要内容。

时间复杂度:考虑常数后为O(slog3n)

代码如下:

<code class="hljs cpp has-numbering"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> MAXN = <span class="hljs-number">65</span>;<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> n, x[MAXN];<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> multi(<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> a, <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> b, <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> p) {    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> ans = <span class="hljs-number">0</span>;    <span class="hljs-keyword">while</span>(b) {        <span class="hljs-keyword">if</span>(b&<span class="hljs-number">1L</span>L) ans = (ans+a)%p;        a = (a+a)%p;        b >>= <span class="hljs-number">1</span>;    }    <span class="hljs-keyword">return</span> ans;}<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> qpow(<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> a, <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> b, <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> p) {    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> ans = <span class="hljs-number">1</span>;    <span class="hljs-keyword">while</span>(b) {        <span class="hljs-keyword">if</span>(b&<span class="hljs-number">1L</span>L) ans = multi(ans, a, p);        a = multi(a, a, p);        b >>= <span class="hljs-number">1</span>;    }    <span class="hljs-keyword">return</span> ans;}<span class="hljs-keyword">bool</span> Miller_Rabin(<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> n) {    <span class="hljs-keyword">if</span>(n == <span class="hljs-number">2</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;    <span class="hljs-keyword">int</span> s = <span class="hljs-number">20</span>, i, t = <span class="hljs-number">0</span>;    <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> u = n-<span class="hljs-number">1</span>;    <span class="hljs-keyword">while</span>(!(u & <span class="hljs-number">1</span>)) {        t++;        u >>= <span class="hljs-number">1</span>;    }    <span class="hljs-keyword">while</span>(s--) {        <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> a = rand()%(n-<span class="hljs-number">2</span>)+<span class="hljs-number">2</span>;        x[<span class="hljs-number">0</span>] = qpow(a, u, n);        <span class="hljs-keyword">for</span>(i = <span class="hljs-number">1</span>; i <= t; i++) {            x[i] = multi(x[i-<span class="hljs-number">1</span>], x[i-<span class="hljs-number">1</span>], n);            <span class="hljs-keyword">if</span>(x[i] == <span class="hljs-number">1</span> && x[i-<span class="hljs-number">1</span>] != <span class="hljs-number">1</span> && x[i-<span class="hljs-number">1</span>] != n-<span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;        }        <span class="hljs-keyword">if</span>(x[t] != <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;    }    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;}</code>
1 0
原创粉丝点击