Files
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

2.0 KiB
Raw Permalink Blame History

AcWing 416. 麦森数

一、考虑如何求位数

我们发现在 x \in (10^k∼10^{k+1}−1) 之间的数均有 k+1 位。对于正整数 $x$,位数等于 $⌊log_{10}x⌋+1$。

而由于$2$的整次幂的末位数字不为$0$,减1并不会使得它位数发生变化,因此 2^{P−1} 的位数和 2^P 的位数相同,所以 2^{P}-1 的位数等于2^{P},等于$⌊log_{10}2^P⌋+1=⌊Plog_{10}2⌋+1$。

$cmath$库中有函数 $log10()$,直接使用即可。

二、考虑如何求最后$500$位数

用快速幂,时间复杂度是 500^2logP=5×10^6

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;

// 高精度乘以高精度模板
int a[N], al;
int b[N], bl;
void mul(int a[], int &al, int b[], int &bl) {
    int c[N] = {0}, cl = al + bl;
    for (int i = 1; i <= al; i++)
        for (int j = 1; j <= bl; j++)
            c[i + j - 1] += a[i] * b[j];

    int t = 0;
    for (int i = 1; i <= al + bl; i++) {
        t += c[i];
        c[i] = t % 10;
        t /= 10;
    }
    memcpy(a, c, sizeof c);
    // 截取尾部有效长度500位
    al = 500;
    // 去除前导0
    while (al > 1 && a[al] == 0) al--;
}

// 快速幂+高精度 x^k
void qmi(int x, int k) {
    a[++al] = 1, b[++bl] = x; // 2 ^100 b[1]=2
    while (k) {
        if (k & 1) mul(a, al, b, bl);
        k >>= 1;
        mul(b, bl, b, bl);
    }
}

int main() {
    // 计算 2^p-1的值
    int p;
    cin >> p;
    // 利用快速幂,计算2^p
    qmi(2, p);
    // 最后一位减去一个1,因为2^k最后一位肯定不是0,所以减1不会产生借位,直接减去即可!
    a[1]--;

    // 一共多少位
    printf("%d\n", (int)(p * log10(2) + 1));

    for (int i = 500; i; i--) {
        printf("%d", a[i]);
        // 该换行了,就是到了第二行的行首
        if ((i - 1) % 50 == 0) puts("");
    }
    return 0;
}