其他分享
首页 > 其他分享> > P1045 [NOIP2003 普及组] 麦森数

P1045 [NOIP2003 普及组] 麦森数

作者:互联网

题目传送门

#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() {
    //计算 2^p-1的值
    int p;
    cin >> p;
    vector<int> A = qmi(2, p);//利用快速幂,计算2^p

    //最后一位减去一个1,因为2^p最后一位肯定不是0,所以减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) printf("\n");
    }
    return 0;
}

//P1045_check.cpp

#include <bits/stdc++.h>
#include<windows.h>

using namespace std;

int main() {
    int t = 1000;
    char file[256];
    //这里的前缀需要每次替换
    string prefix = "P1045";
    while (t) {
        t--;
        system("chcp 65001 > nul");
        sprintf(file, "%s_data.exe  > data.txt", prefix.c_str());
        system(file);

        sprintf(file, "%s.exe < data.txt > %s.txt", prefix.c_str(), prefix.c_str());
        system(file);

        sprintf(file, "%s_right.exe < data.txt > %s_right.txt", prefix.c_str(), prefix.c_str());
        system(file);

        sprintf(file, "fc %s.txt %s_right.txt", prefix.c_str(), prefix.c_str());
        if (system(file)) {
            printf("发现错误时的数据用例:\n");
            system("type data.txt");
            break;
        }
    }
    if (t == 0) cout << "没有检查出错误,测试通过!" << endl;
    return 0;
}

//P1045_data.cpp

#include <bits/stdc++.h>

using namespace std;

int main() {
    srand(time(0));
    int n;
    //n = rand() % 3100000 + 1000;
    n = rand() % (3100000 - 1000) + 1001;
    printf("%d \n", n);
}
//其它测试数据生成办法
//https://blog.csdn.net/Njhemu/article/details/99539576

//P1045_right.cpp

#include <bits/stdc++.h>

using namespace std;
int f[1001], p, res[1001], sav[1001];//乘法要开两倍长度
void result_1() {
    memset(sav, 0, sizeof(sav));
    for (register int i = 1; i <= 500; i += 1)
        for (register int j = 1; j <= 500; j += 1)
            sav[i + j - 1] += res[i] * f[j];//先计算每一位上的值(不进位)
    for (register int i = 1; i <= 500; i += 1) {
        sav[i + 1] += sav[i] / 10;//单独处理进位问题,不容易出错
        sav[i] %= 10;
    }
    memcpy(res, sav, sizeof(res));//cstring库里的赋值函数,把sav的值赋给res
}

void result_2()//只是在result_1的基础上进行了细微的修改
{
    memset(sav, 0, sizeof(sav));
    for (register int i = 1; i <= 500; i += 1)
        for (register int j = 1; j <= 500; j += 1)
            sav[i + j - 1] += f[i] * f[j];
    for (register int i = 1; i <= 500; i += 1) {
        sav[i + 1] += sav[i] / 10;
        sav[i] %= 10;
    }
    memcpy(f, sav, sizeof(f));
}

int main() {
    scanf("%d", &p);
    printf("%d\n", (int) (log10(2) * p + 1));
    res[1] = 1;
    f[1] = 2;//高精度赋初值
    while (p != 0)//快速幂模板
    {
        if (p % 2 == 1)result_1();
        p /= 2;
        result_2();
    }
    res[1] -= 1;
    for (int i = 500; i >= 1; i -= 1)//注意输出格式,50个换一行,第一个不用
        if (i != 500 && i % 50 == 0)printf("\n%d", res[i]);
        else printf("%d", res[i]);
    return 0;
}

标签:麦森数,int,NOIP2003,prefix,vector,file,P1045,txt,500
来源: https://www.cnblogs.com/littlehb/p/15588930.html