P1045 [NOIP2003 普及组] 麦森数

https://www.luogu.com.cn/problem/P1045

首先第一问,输出2p1 的位数

(1)自然数n的位数计算公式推导
n=10 位数是2;
n=100 位数是3;
n=1000 位数是4;
n=12345 位数是5;
小结:自然数n的位数等于log10(n)+1,就也是 lg(n)+1

对数与指数的知识

cout << log10(12345) << endl;        //求10的多少次方是12345
cout << pow(10, 4.09149) << endl; //输出12345 ,表示10的4.09149次方是12345。

以上面的例子来说,lg(12345)+1=lg(12345)+1=4.09149+1=4+1=5

至此,问题转化为求:lg(2p1)+1的值 。

(2)2p1的位数与2p位数的关系
考虑到2p的个位只能是2,4,6,8,不可能出现数字0,所以2p1的位数与2p位数是一样的。也就是说,我们只需要计算出lg(2p)+1就可以知道答案了!

(3)计算lg(2p)+1
这个玩意怎么算呢?利用数学公式lg(mn)=mlg(n)来算,就是plg(2)+1,而lg(2)就是以10为底的2的对数,C++中有现成的计算函数(int) (p * log10(2) + 1)

#include <bits/stdc++.h>
using namespace std;

/*
vector resize解析:
如果n小于当前容器的大小,则将内容减少到其前n个元素,并删除超出范围的元素(并销毁它们)。
如果n大于当前容器的大小,则通过在末尾插入所需数量的元素来扩展内容,以达到n的大小。如果指定了val,则将新元素初始化为val的副本,否则将对它们进行值初始化。
如果n也大于当前容器容量,将自动重新分配已分配的存储空间。
请注意,此函数通过插入或擦除容器中的元素来更改容器的实际内容。
*/

//高精度乘法模板(高精乘高精)
vector<int> mul(vector<int> &A, vector<int> &B) {
    //只保留500个长度
    if(A.size()>500) A.resize(500);    
    if(B.size()>500) B.resize(500);

    int la = A.size(), lb = B.size();
    vector<int> C(la + lb + 10, 0);//提前申请结果所需的空间
    for (int i = 0; i < la; i++)
        for (int j = 0; j < lb; j++)
            C[i + j] += A[i] * B[j];

    for (int i = 0; i < C.size(); i++)
        if (C[i] >= 10) {
            C[i + 1] += C[i] / 10;
            C[i] %= 10;
        }
    //处理前导0
    while (C.size() > 1 && C.back() == 0)C.pop_back();

    //只保留500个长度
    if(C.size()>500) C.resize(500);
    return C;
}

//快速幂+高精度 a^b
vector<int> qmi(int a, int b) {
    vector<int> ans;
    ans.push_back(1);

    vector<int> A;
    A.push_back(a);
    while (b) {
        if (b & 1) ans = mul(ans, A);
        b >>= 1;
        A = mul(A, A);
    }
    return ans;
}

int main() {
    int p;
    cin >> p;
    vector<int> A = qmi(2, p);

    vector<int> B;
    B.push_back(1);

    A[0]--;

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

    //每行输出50位,共输出10行,不足500位时高位补0
    int cnt = A.size();
    for (int i = 0; i < 500 - cnt; i++) A.push_back(0);

    //倒着输出
    for (int i = 500 - 1; i >= 0; i--) {
        printf("%d", A[i]);
        if (i % 50 == 0 && i < A.size() - 1) printf("\n");
    }
    return 0;
}
posted @   糖豆爸爸  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2019-07-09 服务器操作系统与基础软件安装
2019-07-09 Surface 系统恢复
2019-07-09 Python3执行top指令
2019-07-09 IntelliJ IDEA实现远程连接linux,并上传文件到linux服务器(SSH会话功能和SFTP功能)
Live2D
点击右上角即可分享
微信分享提示