梅森素数 | |||
| |||
description | |||
由于梅森学识渊博,才华横溢,为人热情以及最早系统而深入地研究2p-1 型的数(其中p为素数),为了纪念他,数学界就把这种数称为“梅森数”;并以Mp 记之(其中M为梅森姓名的首字母),即Mp=2p-1 。如果梅森数为素数,则称之为“梅森素数”。 比如p=2,3,5,7时,Mp都是素数,但211-1 不是素数 。现在请你求出前N个梅森素数。 | |||
input | |||
有多组测试数据。 第一行是一个正整数T,表示测试数据的组数。接下来每组1个数p的值,这里2<= p <= 62。 | |||
output | |||
对于每组测试数据,判断Mp 是不是梅森素数,是就输出“yes ”,否就输出“no”,输出后要换行。 | |||
sample_input | |||
2 2 7 | |||
sample_output | |||
yes yes |
思路:显然n=2^p-1当p不是素数时n不是梅森数,显然不是素数(可以分解因式反证)
当p是素数即n是梅森数时,需要判定n是不是素数,可以用Lucas-Lehmer测试判定法
涉及知识:
卢卡斯-莱默检验法原理是这样:令梅森数 Mp = 2p− 1作为检验对象(预设p是素数,否则Mp就是合数了)。定义序列{si }:所有的i ≥ 0
-
-
,如果; ,如果。
-
- .
- .
- .
这个序列的开始几项是4, 14, 194, 37634, ... (OEIS中的数列A003010) 那么Mp是素数当且仅当
否则, Mp是合数。sp − 2模Mp的余数叫做p的卢卡斯-莱默余数。
//Accepted 800k 4ms C++ (g++ 3.4.3) 692
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll T,p;
ll multi(ll a,ll b,ll mod)//手写乘法计算,因为直接乘会溢出long long
{
ll ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
b>>=1;
a=(a<<1)%mod;
}
return ans;
}
int main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&p);
ll n=((ll)1<<p)-1;
ll r=4;
if(p==2) puts("yes");//特判
else
{
while((--p)!=1) r=(multi(r,r,n)-2+n)%n;
if(r%n==0) puts("yes");
else puts("no");
}
}
return 0;
}