随手练——麦森数(高精度快速幂)

Posted czc1999

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随手练——麦森数(高精度快速幂)相关的知识,希望对你有一定的参考价值。

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

第一步:求位数

技术图片

第二步:高精度快速幂的实现

第一版:

用vector做的,中间把超过500位的去除,但是实际跑起来比较慢

技术图片
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <algorithm>
using namespace std;

int bits;

void carry(vector<int>& a) {
    for (int i = 0; i < a.size(); i++) {
        if (i != a.size() - 1)a[i + 1] += a[i] / 10;
        else if (a[i] >= 10)a.push_back(a[i] / 10);
        a[i] %= 10;
    }
    while (a.size() > 500) {
        a.pop_back();
        //bits++;
    }
}

void multi(vector<int>& a, vector<int>b) {
    int k = 0;
    vector<int>res(a.size());
    for (int i = 0; i < b.size(); i++) {
        for (int j = 0; j < a.size(); j++) {
            if (k + j >= res.size())
                res.push_back(0);
            res[k + j] += a[j] * b[i];
        }
        k++;
    }
    carry(res);

    a = res;
}

void quick_power(vector<int>& a, int k) {
    vector<int>res;
    res.push_back(1);
    while (k) {
        if (k & 1)
            multi(res, a);
        k >>= 1;
        if(k)
        multi(a, a);
    }
    a = res;
}

int main() {
    int p, k = 1;
    cin >> p;
    vector<int>a, b;
    a.push_back(2); 
    cout << (int)(log10(2) * p + 1) << endl;
    quick_power(a, p);
    
    if (a.size() < 500) {
        for (int i = a.size(); i < 500; i++, k++) {
            cout << 0;
            if (k % 50 == 0)cout << endl;
        }
    }
    a[0] -= 1;
    
    for (int i = a.size() - 1; i >= 0; i--, k++) {
        cout << a[i];
        if (k % 50 == 0)cout << endl;
    }
    cout << endl;
    return 0;
}
View Code

第二版: 

直接用int数组,循环全都是到500停止,锁死了时间上限,当p大的时候,确实非常快,不过可读性稍微差了一点。

技术图片
#include <iostream>
#include <string.h>
#include <math.h>

using namespace std;

int a[1001] = { 2 }, b[1001], res[1001], temp[1001];

void carry(int *arr) {
    for (int i = 0; i < 500; i++) {
        arr[i + 1] += arr[i] / 10;
        arr[i] %= 10;
    }
}

void multi(int* a, int* b, int* res) {
    memset(temp, 0, sizeof(temp));
    for (int i = 0; i < 500; i++) {
        for (int j = 0; j < 500; j++) {
            temp[i + j] += a[j] * b[i];
        }
    }
    carry(temp);
    memcpy(res, temp, sizeof(temp));
}

void quick_power(int k) {
    res[0] = 1;
    while (k) {
        if (k & 1)
            multi(res, a, res);
        k >>= 1;
        if (k)
            multi(a, a, a);
    }
}

int main() {
    int p, k = 1;
    cin >> p;
    int bits = (int)(log10(2) * p + 1);
    cout << bits << endl;
    quick_power(p);
    //2^n次方,不可能为0,所以可以直接减1
    res[0] -= 1;
    for (int i = 499; i >= 0; i--, k++) {
        cout << res[i];
        if (k % 50 == 0)cout << endl;
    }
    cout << endl;
    return 0;
}
View Code

很奇怪的是,测试数据中一个很大的p值,本地跑起来,第一版要等5s左右,第二版几乎瞬间就出来了,交OJ,时间的差别不是很大。

以上是关于随手练——麦森数(高精度快速幂)的主要内容,如果未能解决你的问题,请参考以下文章

快速幂+分治(洛谷P1045 麦森数 noip2003)

高精度乘法NOIP2003麦森数

麦森数

算法训练 麦森数

noip2003 麦森数

题解[P1045] 麦森数