nefu 120 梅森素数

题意:给出p(1<p<=62),让你求Mp=2^p-1是否为梅森素数。

梅森素数:若p为素数,且Mp=2^p-1也是素数,则Mp为梅森素数。
若p为合数,Mp=2^p-1一定为合数
若p为素数,Mp=2^p-1不一定为素数

判别梅森素数
1.卢卡斯-莱默判别法:
设p为素数,Mp=2^p-1,R0=4。
Rk=(Rk-1)^2-2(mod Mp) 0<=Rk<Mp,k>=1
可以得到Rk的序列,k=0,1,2,...,p-2。
Mp为素数,当且仅当,Rp-2=0(mod Mp)

2.Miller素数测试法

我采用的是第一种,较为简单。第二种书上的没看懂,而且有些地方还印刷错误!!!。。。其实第一种对于我这个数学渣渣,我也不知道怎么证啦

详解请见《ACM-ICPC程序设计系列  数论及应用》

 

#include <iostream>
#include <cstdio>
#include <string.h>

using namespace std;
int t,p;
bool isprime[70];

void init() {
    memset(isprime,true,sizeof(isprime));
    for(int i=2; i*i<70; i++) {
        if(isprime[i]) {
            for(int j=i*2; j<70; j+=i)
                isprime[j]=false;
        }
    }
}
long long quickPow(long long a,int b) {
    long long ans=1;
    while(b) {
        if(b&1)
            ans=ans*a;
        a=a*a;
        b=b/2;
    }
    return ans;
}
//由于a*b可能会超出long long的范围,所以这里将乘法换成加法取模运算
//想法妙啊!!!
long long quickPlus(long long a,long long b,long long mod) {
    long long ans=0;
    while(b) {
        if(b&1)
            ans=(ans+a)%mod;
        b=b/2;
        a=(a<<1)%mod;
    }
    return ans;
}
int main() {
    init();
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&p);
        if(isprime[p]) {
            long long r=4;
            long long Mp=quickPow(2,p)-1;
            long long tmp;
            for(int i=1; i<=p-2; i++) {
                tmp=quickPlus(r,r,Mp);
                r=((tmp-2)%Mp+Mp)%Mp;
            }
            if(!r||p==2)  //2作为特判
                printf("yes\n");
            else
                printf("no\n");
        } else {
            printf("no\n");
        }
    }
    return 0;
}
View Code

 

posted @ 2014-02-16 18:57  辰曦~文若  阅读(243)  评论(0编辑  收藏  举报