标签:高精度、快速幂
【思路】
此题主要分为两个部分,第一个部分是求位数,第二部分是求最后500位数字。
-
求位数,并不用把整个结果全部算出来。我们知道一个高中学过的公式 N l o g N X = X N^{log_{N}{X}} = X NlogNX=X。所以对于 2 P − 1 2^{P}-1 2P−1可以转换成 1 0 l o g 10 2 P − 1 10^{log_{10}^{2^{P}-1}} 10log102P−1,另外2的次方最后一位肯定不为零,所以减一后位数并不会改变,又可以化为 1 0 l o g 10 2 P 10^{log_{10}^{2^{P}}} 10log102P ,因此位数 k = l o g 10 2 P + 1 = P ∗ l o g 10 2 + 1 k = log_{10}^{2^{P}} + 1 = P*log_{10}^{2} + 1 k=log102P+1=P∗log102+1。
-
求最后500位数字,不用计算大于500位的。如果只用高精度计算(每次乘2),会有四个点超时。所以改进方法是结合高精度和快速幂。
便于理解: 下面代码是普通的快速幂运算。对于本题的代码,muti1()相当于计算 result *= a; ,muti2()相当于计算 a *= a; ,不同之处只是先用tmp临时存起计算结果,再复制给相应的result和a。
int quickPower(int a, int b) //是求a的b次方
{
int result = 1;
while (b > 0) //最后化成1次方
{
if (b % 2 == 1) //循环最后一次b=1,肯定会执行,即把结果存储在result中
result *= a;
a *= a;
b /= 2;
}
return result;
}
【代码】
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int p, res[1005], a[1005];
int tmp[1005]; // 临时存储
void muti1() {
memset(tmp, 0, sizeof(tmp));
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 500; j++) {
tmp[i + j] += res[i] * a[j];
}
}
for (int i = 0; i < 500; i++) {
tmp[i + 1] += tmp[i] / 10;
tmp[i] %= 10;
}
memcpy(res, tmp, sizeof(tmp));
}
void muti2() {
memset(tmp, 0, sizeof(tmp));
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 500; j++) {
tmp[i + j] += a[i] * a[j];
}
}
for (int i = 0; i < 500; i++) {
tmp[i + 1] += tmp[i] / 10;
tmp[i] %= 10;
}
memcpy(a, tmp, sizeof(tmp));
}
int main() {
cin >> p;
cout << int(p*log10(2)) + 1;
res[0] = 1;
a[0] = 2;
while (p > 0) {
if (p % 2 == 1) {
muti1();
}
muti2();
p /= 2;
}
res[0]--; // 2^p-1中的减1
for (int i = 500; i > 0; i--) { // 打印
if (i % 50 == 0) {
cout << endl << res[i - 1];
}
else {
cout<< res[i - 1];
}
}
cout << endl;
return 0;
}