P1045 麦森数(高精度快速幂取模)

26 篇文章 2 订阅

题目链接:

https://www.luogu.org/problemnew/show/P1045

题意:

输入格式:

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

输出格式:

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

第2-11行:十进制高精度数2^P−1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)

不必验证2^P−1与P是否为素数。

题解:

1、首先需要输出位数,这里给大家推导一个公式可以直接计算2^n的位数(同样也可以计算n^k的位数)

先给出公式:2^k的位数就是\left \lfloor {klog_{10}}^{2} \right \rfloor + 1

证明:

 10 ^ \left \lfloor k \right \rfloor   <=  10^{k}  <= 10 ^ \left \lceil k \right \rceil   , 所以10^{k} 的位数是:\left \lfloor k \right \rfloor + 1
再举个通俗栗子:10 ^ 3  <  10 ^ 3.5 < 10^4,10的四次方是5位数(10000),10^3.5 次方小于 10000,且大于1000 所以是四位数,也就是 3.5取下整加 1 .

知道10^{k} 怎么求位数了,那就把 n^{k}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​10^{k} 转化为 10^{k} 的形式:
n^{k}= 10^{log_{10}}^{n^{k}}
n^{k}= 10^{klog_{10}}^{n}
所以n^{k}的位数就是\left \lfloor {klog_{10}}^{n} \right \rfloor + 1
所以2^k的位数就是\left \lfloor {klog_{10}}^{2} \right \rfloor + 1

2、其次需要利用高精度进行模运算和取余数的工作,如代码所示:

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define MAXN ((int)1e5 + 10)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int a[2600];
int b[2600];
int r[2600];
void mul(int *a, int *b)
{
    memset(r, 0, sizeof(r));
    for(int i = 0; i < 500; i++){
        int before = 0;  //进的位数
        for(int j = 0; j < 500; j++){
            r[i + j] += a[i] * b[j] + before; // 通过 i + j 模拟乘法到了第几位了,从左到右存
            before = r[i + j] / 10;  //进位
            r[i + j] = r[i + j] % 10;
        }
        if(before) r[i + 500] += before;//最后如果还有就把最后需要进的位加上
    }
}

void power(int p)
{
    memset(b, 0, sizeof(b));
    b[0] = 2;//底数
    while(p)
    {
        if(p & 1){
            mul(a, b);
            for(int i = 0; i < 500; i++) a[i] = r[i]; // 取余数
        }
        mul(b, b);
        for(int i = 0; i < 500; i++) b[i] = r[i];// 取余数
        p = p >> 1;
    }
}

int main()
{
    int p; cin>>p;
    a[0] = 1;  //初始化为 1
    power(p);
    a[0]--;// 2^p - 1  减的那个1
    cout<<(int)(p*log10(2)+1)<<'\n';
    for(int i = 499; i >= 0; i--){
        printf("%d", a[i]);
        if(i % 50 == 0) puts("");
    }
}

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值