专栏文章

题解:P1045 [NOIP 2003 普及组] 麦森数

P1045题解参与者 9已保存评论 8

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
8 条
当前快照
1 份
快照标识符
@mip4f5na
此快照首次捕获于
2025/12/03 05:59
3 个月前
此快照最后确认于
2025/12/03 05:59
3 个月前
查看原文
这道题目看上去十分简单,只需要算出 2p1mod105002^p-1\mod10^{500} 的值就可以了,看似是一道高精度模板题
但是当我们写好高精度的时候就会发现超时了,PP 的最大值会达到 31000003100000,乘以要维护的 500500 位数,就达到了 1.55×1091.55\times10^9 次的运算。因此我们需要改进。
改进的方法有很多,例如在高精度乘法时不是每次乘以 22,而是 2n2^n。考虑到 unsigned long long最多只能够表示 26412^{64}-1,我们可以每 2602^{60} 进行一次乘法,这样所需要的运算次数就降低到了约 2.58×1072.58\times10^7,已经是在可接受范围内了。
另外计算位数,我们可以通过对数的基本性质:logabn=nlogab\log_a{b^n}=n\log_ab,把 2P2^P 的计算回避掉,从而变成 plg2+1\lfloor p\lg2\rfloor+1
综上所述,就可以得到以下代码:
CPP
#include <iostream>
#include <cmath>
using namespace std;
unsigned long long a[510] = {0, 1}, t;
int p;
int main()
{
    cin >> p;
    cout << (int)(p * log10(2)) + 1 << endl;
    for (; p >= 0; p -= 60)
    {
        t = 0;
        for (int j = 1; j <= 500; j++)
        {
            if (p >= 60) a[j] <<= 60;
            else a[j] <<= p;
            a[j] += t;
            t = a[j] / 10;
            a[j] %= 10;
        }
    }
    a[1] -= 1;
    for (int i = 500; i >= 1; i--) 
    {
        cout << (char)('0' + a[i]);
        if (i % 50 == 1) cout << endl;
    }
    return 0;
}

评论

8 条评论,欢迎与作者交流。

正在加载评论...