前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >素数判定(素数)- HDU 2012

素数判定(素数)- HDU 2012

作者头像
ACM算法日常
发布2018-08-07 18:23:14
1.3K0
发布2018-08-07 18:23:14
举报
文章被收录于专栏:ACM算法日常ACM算法日常

刚学编程的时候,我们大多需要做的一道题,那就是用C语言来判定一个数是否是素数。那时候很自然的会想到,对于数n,直接遍历一下n以下的数x,如果n%x等于0,说明可以被整除,也就不是素数。

这个是一个很正常的思维,因为不会理论数学分析的我们,很难想象得到我们可以用第二种方式解决这个问题,那就是开根号。

计算机专业书《离散数学及其应用》里面有一个委婉的定理,定理如下:

定理2:如果n是一个合数,那么必有一个素因子小于或等于sqrt(n)。

从定理2可知,如果一个整数不能被小于或等于其平方根的素数整除,则它就是素数 。

OK,我们的第二种解法就是遍历小于sqrt(n)的数。

但是,对于搞数学的来说,这个还是太慢了,因为他们研究的数字往往都是天文数字。

于是经过种种努力与机缘巧合,米勒·罗宾两个人研究出了一个测试算法,该算法也因此以他们的名字命名。

米勒·罗宾测试的错误率至多为1/2的s次方,s为迭代次数。数学家可能喜欢把s搞到20-50,程序员弄个4-10就可以了。

目前来说,这个算法是最快的!

这个算法可以看《算法导论》,里面讲得很详细,离散数学里面没有讨论这个算法,可见算法导论在追求性能的理论方面是做到了极致的。

算法思路如下。

另外一个想说的事情是,数学方面的题目由于理论性太强,就比如之前的hash函数,也是数学上面的结论,我们很难真正从本质是去理解为什么,也因此在源码中不做这方面的注释工作,数学方面的结论就当是模板函数,如果你天资聪颖,建议你还是花时间去看看。

好了,来看题。

Problem Description

对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。

Input

输入数据有多组,每组占一行,由两个整数x,y组成,当x=0,y=0时,表示输入结束,该行不做处理。

Output

对于每个给定范围内的取值,如果表达式的值都为素数,则输出"OK",否则请输出“Sorry”,每组输出占一行。

Sample Input

0 1

0 0

Sample Output

OK

解题说明:对于任意的输入,测试一下即可。

源代码:G++ 0ms

代码语言:javascript
复制
#include<stdlib.h>
#include<stdio.h>

/***************米勒·罗宾***************/
#define MAXN 65
long long n, x[MAXN];
//multi函数网上还有一种实现,速度为O(1)
long long multi(long long a, long long b, long long p) {
    long long ans = 0;
    while (b) {
        if (b & 1LL) ans = (ans + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return ans;
}

long long qpow(long long a, long long b, long long p) {
    long long ans = 1;
    while (b) {
        if (b & 1LL) ans = multi(ans, a, p);
        a = multi(a, a, p);
        b >>= 1;
    }
    return ans;
}

int miller_rabin(long long n, int iterate) {
    if (n == 2) return 1;
    if (n % 2 == 0) return 0;
    int s = iterate, i, t = 0;
    long long u = n - 1;
    while (!(u & 1)) {
        t++;
        u >>= 1;
    }
    while (s--) {
        long long a = rand() % (n - 2) + 2;
        x[0] = qpow(a, u, n);
        for (i = 1; i <= t; i++) {
            x[i] = multi(x[i - 1], x[i - 1], n);
            if (x[i] == 1 && x[i - 1] != 1 && x[i - 1] != n - 1) return 0;
        }
        if (x[t] != 1) return 0;
    }
    return 1;
}
/***************米勒·罗宾·end***************/

int main()
{
    int x, y;
    //米勒·罗宾算法迭代次数
    const int iterate = 4;
    //输入x、y
    while (scanf("%d%d", &x, &y) && x | y) {
        //是否全部是素数
        int is_all_prime = 1;

        for (int i = x; i <= y; ++i) {
            //进行米勒·罗宾素数测试
            if (!miller_rabin(i * i + i + 41, iterate)) {
                is_all_prime = 0;
                break;
            }
        }

        printf("%s\n", is_all_prime ? "OK" : "Sorry");
    }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ACM算法日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档