麦森数

本文介绍了一种高效计算2^P-1的位数及其最后500位的方法,通过高精度计算和二进制分解技巧,实现了对大数的有效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:计算2^P-1的位数和它的最后500位并输出。
1、计算位数:2^P-1的位数为[log10(2^P)]+1==[Plog10(2)]+1
2、计算最后500位:高精度预处理2^i,计算时将P分解成二进制形式,然后相乘,只保留500位

代码一:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#define N 126
using namespace std;
int ans[N],anspow[N];
void mult(int ans[],int anspow[])
{
  int i,j;
  int c[N];
  memset(c,0,sizeof(c));
        for(i=0;i<N;i++)  
        {  
            for(j=0;j<N;j++)                  
            {  
                if(i+j<N)//超出500位的部分不计算
                {
                  c[i+j]+=ans[j]*anspow[i]; 
                }                              
            }  
           for(j=0;j<N-1;j++)  
           {  
                if(c[j]>=10000) 
                {  
                    c[j+1]+=c[j]/10000;//压4位  
                     c[j]%=10000;              
                }                    
           }  
        }  
        memcpy(ans,c,N*sizeof(int));  //复制函数
}
int main()
{
  int P,i,j;
  while(cin>>P)
  {
    memset(ans,0,sizeof(ans));
    memset(anspow,0,sizeof(anspow));
    printf("%d\n",(int)(P*log10(2)+1));
    ans[0]=1;
    anspow[0]=2;
/************关键部分计算2^P*******
 2^p=(2^1)*(2^2)*(2^3)*(2^4)*(2^5)………………
 简单说下:P=5 -----101(二进制)
    p & 1 =1(最右边一位) -->>>ans=2 anspow=2
    p>>1=110  anspow=2^2
    p & 1 =0  此时表明2^3不存在 ans=2 anspow=2^4
    p>>1=1       
    p & 1 =1  ------>>>>> ans=2^5 
    p>>1=0   ------结束    
************************************/
    while(P)
    {
        if( P & 1)
            mult(ans,anspow);
        P>>=1;
            mult(anspow,anspow);
    }
    ans[0]--;//2^P的个位为2,4,6,8,故可以-1
/****************输出格式的控制************************/
    for(i=124;i>=0;i--)
    {
        if(i%25==12)  
        {
           printf("%02d\n%02d",ans[i]/100,ans[i]%100);  
        }
        else  
        {  
           printf("%04d",ans[i]);
           if(i%25==0) printf("\n");
        }     
    }
/***************************************************/
  }
return 0;
}
代码二:

/*************麦森数****************/
#include<iostream>
#include<cstdio>
#include<cmath>
#define N 100   //压5位
using namespace std;
int ans[N];
void  mult(int t)
{
  int i,temp,last=0;
      for ( i=N-1; i>=0; i--)
    { 
        temp=(ans[i]<<t)+last;   //乘2^t,加进位 
        last=temp/100000; 
        ans[i]=temp-last*100000;  //temp%100000 
    } 
}
void output()
{
   int i;
   for(i=1;i<=N;i++)
   {     printf("%05d",ans[i-1]);
        if (i%10==0)cout<<endl;   
   } 
}
int main()
{
  int P,times;
  while(cin>>P)
  {
      memset(ans,0,sizeof(ans));
      ans[N-1]=1;
      cout<<(int)(P*log10(2)+1)<<endl;
/***********************关键部分*****************
  2^P=2^(14*times)*2^(P%14) 用移位
  之所以取14的原因 2^14*(99999)=1.638382*10^9 在(int)
  范围,15以后都会超int,主要体现在mult()中      
 **********************************************/
      times=P/14;  //只能到14 15以后压缩时会超范围
      while(times--)
          mult(14);
       mult(P%14);
       --ans[99];
      output();
  }
return 0;
}

转自:http://www.cnblogs.com/lsx54321/archive/2012/07/25/2608414.html

### 关于洛谷 P1045 麦森 的解题思路 #### 一、问题分析 该问题的核心在于处理大整运算以及高精度计算。具体来说,给定一个素 \(P\) (\(1000 < P < 3100000\)),需要完成两部分任务: 1. **计算 \(2^P - 1\) 的位数** 这可以通过学公式推导得出:对于任意正整 \(n\) 和基 \(b\) (通常为10),其位数可以由 \(\lfloor \log_{10}(n) \rfloor + 1\) 计算得到[^1]。 2. **求取 \(2^P - 1\) 的最后 500 位数字** 此处涉及高精度乘法操作,因为直接存储如此巨大的值是不可能的。 --- #### 二、解决方法详解 ##### 1. 计算 \(2^P - 1\) 的位数 利用对性质,可以直接通过如下公式快速计算出 \(2^P - 1\) 的位数: \[ D = \lfloor P \cdot \log_{10}2 \rfloor + 1 \] 其中,\(\log_{10}2\) 是常量,约等于 0.30103[^2]。因此无需实际进行幂次运算即可获得结果。 ##### 2. 获取 \(2^P - 1\) 的最后 500 位数字 由于 \(2^P - 1\) 极其庞大,无法直接存入标准据类型中,需采用高精度算法模拟手工乘法过程来逐步构建目标值。以下是主要步骤: - 初始化组用于保存每一位的结果; - 使用循环迭代方式不断累加中间结果; - 对最终结果减去 1 并截取出后 500 位作为输出。 下面是基于 Python 实现的一个高效版本代码示例: ```python import math def calculate_mersenne_number(p, last_digits_count=500): # Step 1: Calculate the number of digits in 2^p - 1 num_digits = int(math.floor(p * math.log10(2))) + 1 # Initialize a list to store high precision result with initial value as [1] res = [1] # Perform fast exponentiation using repeated squaring method power = p base = 2 % (10 ** last_digits_count) while power > 0: if power & 1: temp_res = [] carry = 0 for digit in res: mul = digit * base + carry temp_res.append(mul % (10 ** last_digits_count)) carry = mul // (10 ** last_digits_count) if carry > 0: temp_res.append(carry) res = temp_res[:] square_carry = 0 squared = [] for digit in res: sq = digit * digit + square_carry squared.append(sq % (10 ** last_digits_count)) square_carry = sq // (10 ** last_digits_count) if square_carry > 0: squared.append(square_carry) res = squared[:] base = (base * base) % (10 ** last_digits_count) power >>= 1 # Subtract one from the final result and adjust it accordingly. borrow = 1 for i in range(len(res)): idx = len(res) - 1 - i new_val = res[idx] - borrow if new_val >= 0: res[idx] = new_val break else: res[idx] = new_val + (10 ** last_digits_count) # Convert the result into string format by reversing each part appropriately. str_result = ''.join([f"{digit}".zfill(last_digits_count)[-last_digits_count:] for digit in reversed(res)]) return num_digits, str_result[-last_digits_count:] # Example usage if __name__ == "__main__": p_value = 3021377 # Given prime number P total_digits, last_500_digits = calculate_mersenne_number(p_value) print(f"Total Number of Digits: {total_digits}") print(f"Last 500 Digits:\n{last_500_digits}") ``` 上述程序实现了两个功能模块——分别负责计算总位数和提取指定长度尾部序列[^3]。 --- #### 三、总结说明 此方案综合运用了学理论简化复杂度较高的指运算环节,并借助编程技巧完成了必要的高精度过载支持。这种方法不仅适用于本题情境下超大规模值场景下的精确表达需求,在其他类似领域同样具备广泛适用价值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值