NOIP2003 普及组 麦森数
题目描述
形如 2 P − 1 2^{P}-1 2P−1 的素数称为麦森数,这时 P P P 一定也是个素数。但反过来不一定,即如果 P P P 是个素数, 2 P − 1 2^{P}-1 2P−1 不一定也是素数。到 1998 年底,人们已找到了 37 个麦森数。最大的一个是 P = 3021377 P=3021377 P=3021377,它有 909526 位。麦森数有许多重要应用,它与完全数密切相关。
任务:输入 P ( 1000 < P < 3100000 ) P(1000<P<3100000) P(1000<P<3100000),计算 2 P − 1 2^{P}-1 2P−1 的位数和最后 500 500 500 位数字(用十进制高精度数表示)
输入格式
文件中只包含一个整数 P ( 1000 < P < 3100000 ) P(1000<P<3100000) P(1000<P<3100000)
输出格式
第一行:十进制高精度数 2 P − 1 2^{P}-1 2P−1 的位数。
第 2 ∼ 11 2\sim 11 2∼11 行:十进制高精度数 2 P − 1 2^{P}-1 2P−1 的最后 500 500 500 位数字。(每行输出 50 50 50 位,共输出 10 10 10 行,不足 500 500 500 位时高位补 0 0 0)
不必验证 2 P − 1 2^{P}-1 2P−1 与 P P P 是否为素数。
样例 #1
样例输入 #1
1279
样例输出 #1
386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087
提示
【题目来源】
NOIP 2003 普及组第四题
解题思路
- 十进制位数公示
- 高精度 * 高精度
- 快速幂
AC代码
/**
* @problem: P1045 [NOIP2003 普及组] 麦森数
* @link: https://www.luogu.com.cn/problem/P1045
* @category: math 高精度
* @date:
* @Author: YaeSaraki
**/
#include <algorithm>
#include <iostream>
#include <vector>
#include <ranges>
#include <cmath>
#define ALL(v) v.begin(), v.end()
#define DBG(x) std::cout << #x << " = " << (x) << '\n'
//#define int long long
using ll = long long;
using PI = std::pair<int, int>;
std::vector<int> sub(std::vector<int> &a, std::vector<int> &b) {
/* A >= B */
int t = 0;
std::vector<int> c;
for (int i = 0; i < a.size(); ++i) {
t = a[i] - t;
if (i < b.size()) t -= b[i];
c.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}
while (c.size() > 1 && c.back() == 0) c.pop_back();
return c;
}
/** 高精度 * 高精度 */
std::vector<int> mul(std::vector<int> &a, std::vector<int> &b) {
int t = 0;
std::vector<int> c(500);
/* 丢弃高于501位的数 */
for (int i = 0; i < std::min((int)a.size(), 500); ++i) {
for (int j = 0; j < std::min((int)b.size(), 500); ++j) {
if (i + j < 500) c[i + j] += a[i] * b[j];
}
}
/* 进位处理 */
for (int i = 0; i < c.size(); ++i) {
if (c[i] > 9) {
c[i + 1] += c[i] / 10;
c[i] %= 10;
}
}
while (c.size() > 1 && c.back() == 0) c.pop_back();
return c;
}
/** 快速幂 */
std::vector<int> qPow(std::vector<int> &a, int n) {
std::vector<int> ans = {1};
while (n) {
if (n & 1) ans = mul(ans, a);
a = mul(a, a);
n >>= 1;
}
return ans;
}
inline void solve() {
int n; std::cin >> n;
std::vector<int> a = {2};
/* 快速幂求2 ^ n */
a = qPow(a, n);
/* 减去1 */
std::vector<int> b = {1};
a = sub(a, b);
/* 输出位数 */
std::cout << (int)(log10(2) * n) + 1 << '\n';
/* 处理答案位数 */
while (a.size() != 500) {
while (a.size() > 500) a.pop_back();
while (a.size() < 500) a.push_back(0);
}
/* 输出 */
for (int i = 499; ~i; --i) {
std::cout << a[i];
/* 注意50一行 */
if (i % 50 == 0) std::cout << "\n";
}
}
bool rt = false;
signed main() {
std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif
if (rt) { int T; std::cin >> T; while (T--) solve(); }
else solve();
return (0 ^ 0);
}