题目描述
求(2^P - 1)的后五百位,且输出(2^P - 1)的位数,其中(1000<P<3100000)
输出
第一行:十进制高精度数 (2^{P}−1) 的位数。
第2-11行:十进制高精度数 (2^{P}−1) 的最后500位数字。
(每行输出50位,共输出10行,不足500位时高位补0)
不必验证 (2^{P}−1) 与(P)是否为素数。
分析
1. 求数的位数
假设(x = 2^P - 1),即求(x)的位数,因为(2^P)的最后一位一定大于1。
所以(2^P)的位数与(x)的位数相同。
(len = lg{x} + 1 = lg{2^P} + 1 = P*lg{2} + 1)
例如100
的长度为(lg100 + 1 = 2 +1 = 3)
所以长度的计算方法为
len = (int)(p * lg10(2)) + 1
2. 两个高精度数的乘法
const int N = 1e3 + 10; // 因为输出的长度为500, 500 + 500 = 1000
vector<int> mul(vector<int> A, vector<int> B) {
vector<int> C(N, 0);
for (i = 0; i < 500; i++)
for (j = 0; j < 500; j++)
C[i + j] += C[i] * C[j];
for (j = 0; j < 500; j++) {
C[j + 1] += C[j] / 10;
C[j] = C[j] % 10;
}
return C;
}
3. 快速幂
使用快速幂对空间复杂度进行优化
int p; // p为输入的阶
vector<int> t(N, 0); // 保存2^1 2^2 2^4
vector<int> res(N, 0); // 结果
t[0] = 2; // 初始化
res[0] = 1;
while (p) {
if (p & 1) // 如果p的2进制最后一个位为1
res = mul(res, t);
t = mul(t * t);
p >>= 1;
}
4. 输出
for (int i = 0, k = 499; i < 10; i++) {
for (int j = 0; j < 50; j++, k--) {
if (k) printf("%d", res[k]);
else printf("%d", res[k] - 1);
}
puts("");
}
完整代码
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
const int N = 1000 + 10;
vector<int> mul(vector<int> &A, vector<int> &B) {
vector<int> C(N, 0);
for (int i = 0; i < 500; i++)
for (int j = 0; j < 500; j++)
C[i + j] += A[i] * B[j];
// printf("%d ", i + j);
for (int j = 0; j < 500; j++) {
C[j + 1] += C[j] / 10;
C[j] %= 10;
}
return C;
}
int main() {
int p;
scanf("%d", &p);
vector<int> res(N, 0);
vector<int> t(N, 0);
t[0] = 2; res[0] = 1;
printf("%d
", (int)(p * log10(2)) + 1);
while (p) {
if (p & 1)
res = mul(res, t);
t = mul(t, t);
p >>= 1;
}
for (int i = 0, k = 499; i < 10; i++) {
for (int j = 0; j < 50; j++, k--) {
if (k) printf("%d", res[k]);
else printf("%d", res[k] - 1);
}
puts("");
}
return 0;
}