EH's Blog

题目情境#

题目链接:https://www.luogu.com.cn/problem/P1045 ↗

题目描述

形如 2P−12^{P}-1 的素数称为麦森数,这时 PP 一定也是个素数。但反过来不一定,即如果 PP 是个素数,2P−12^{P}-1 不一定也是素数。到 1998 年底,人们已找到了 37 个麦森数。最大的一个是 P=3021377P=3021377,它有 909526 位。麦森数有许多重要应用,它与完全数密切相关。

任务:输入 P(1000<P<3100000)P(1000<P<3100000),计算 2P−12^{P}-1 的位数和最后 500500 位数字(用十进制高精度数表示)

输入格式

文件中只包含一个整数 P(1000<P<3100000)P(1000<P<3100000)

输出格式

第一行:十进制高精度数 2P−12^{P}-1 的位数。

第 2∼112\sim 11 行:十进制高精度数 2P−12^{P}-1 的最后 500500 位数字。(每行输出 5050 位,共输出 1010 行,不足 500500 位时高位补 00)

不必验证 2P−12^{P}-1 与 PP 是否为素数。

输入 #1

1279
plaintext

输出 #1

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087
plaintext

算法解析:#

麦森数:位数由 ⌊Plog⁡102⌋+1\lfloor P\log_{10}2\rfloor+1 计算。后 500 位用高精度数组 + 快速幂:乘法按位逐位计算并进位,幂次按二进制拆分,最后个位减 1(2P−12^P-1)。输出分 10 行,每行 50 位。

Python代码实现#

import sys
N = 500
def mul(a, b):  # 高精度乘法
    t = [0] * (N * 2)
    for i in range(N):
        for j in range(N):
            t[i + j] += a[i] * b[j]
            t[i + j + 1] += t[i + j] // 10
            t[i + j] %= 10
    return t
def quickpow(p):  # 快速幂
    a = [0] * N
    res = [0] * N
    a[0] = 2
    res[0] = 1
    while p:
        if p & 1:
            res = mul(res, a)
        a = mul(a, a)
        p >>= 1
    res[0] -= 1  # 个位修正
    return res
def main():
    p = int(sys.stdin.readline())
    # 输出位数
    print(int(p * __import__('math').log10(2)) + 1)

    res = quickpow(p)
    for i in range(10):
        start = N - 1 - i * 50
        line_digits = res[start - 49:start + 1]
        print(''.join(str(d) for d in reversed(line_digits)))
if __name__ == '__main__':
    main()
python

C++代码实现#

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

const int N=500;
typedef vector<int> VI;
VI a(N),res(N);
int p;

VI mul(VI &a, VI &b){//高精度
  VI t(N*2);
  for(int i=0; i<N; i++)
    for(int j=0; j<N; j++){
      t[i+j] += a[i]*b[j];
      t[i+j+1] += t[i+j]/10;
      t[i+j] %= 10;
    }
  return t;
}
void quickpow(int p){//快速幂
  res[0]=1, a[0]=2;
  while(p){
    if(p & 1) res = mul(res,a);
    a = mul(a,a);
    p >>= 1;
  }
  res[0]--; //个位修正
}
int main(){
  cin >> p;
  printf("%d\n",int(p*log10(2))+1);
  quickpow(p);
  for(int i=0, k=499; i<10; i++){
    for(int j=0; j<50; j++, k--)
      printf("%d",res[k]);
    puts("");
  }
  return 0;
}
c
G2 高精度快速幂
https://ehnotgod.site/zh/blog/g2-%E9%AB%98%E7%B2%BE%E5%BA%A6%E5%BF%AB%E9%80%9F%E5%B9%82
Author EH
Published at August 8, 2026