1 題目
問題描述
形如 的素數稱爲麥森數,這時 一定也是個素數。但反過來不一定,即如果 是個素數, 不一定也是素數。到1998年底,人們已找到了37個麥森數。最大的一個是 ,它有 位。麥森數有許多重要應用,它與完全數密切相關。
任務:從文件中輸入 ,計算 的位數和最後 位數字(用十進制高精度數表示)
輸入格式
文件中只包含一個整數 (1000<P<3100000)
輸出格式
第一行:十進制高精度數 的位數。
第2-11行:十進制高精度數 的最後500位數字.(每行輸出50位,共輸出10行,不足500位時高位補0)
不必驗證 與 是否爲素數。
樣例輸入
1279
樣例輸出
386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087
2 題目分析
1.題目難點:
- 求 的位數
- 高精度算法
- 二分快速冪實現
2.求 的位數
- 首先要知道的是 與 有相同的位數,因此接下來我們直接求 的位數
- 不妨設
- 我們知道, 的位數爲 ,而根據對數運算規則,
- 因此將 代入 得 ,所以 的位數爲
- 另外,C++ 的 cmath 庫中自帶 log10() 函數。也有直接計算位數的函數:ceil(n次方*log10(底數))
3.高精度算法
-
在 C/C++ 中, 類型有10位,取值範圍爲:; 類型有19位,取值範圍爲:
-
如果有兩個30位的數字相乘,應該如何用計算機實現?
-
這就是高精度乘法的應用,以高精度加法舉例,就是用數組存儲數字每一位的數字,逐個運算,具體的算法可參考博客:高精度加、減、乘、除算法實現詳解
-
在本題中,就是運用高精度乘法的原理實現二分快速冪過程。
4.二分快速冪實現
- 快速冪原理:https://blog.csdn.net/liangllhahaha/article/details/82119378
- 在本題中,用兩個函數實現快速冪中 ans *= base 與 base *= base 的功能,其中 則爲冪方 ,數組 b[maxn] 爲基數 base
3 題解
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
//乘法開2倍長度
const int maxn = 1001;
int ans[maxn], b[maxn], carry[maxn], p;
void fun1(){
memset(carry, 0, sizeof(carry));
for(int i = 1;i <= 500;i++){
for(int j = 1;j <= 500;j++){
carry[i + j - 1] += ans[i] * b[j];
}
}
for(int i = 1;i <= 500;i++){
carry[i + 1] += carry[i] / 10;
carry[i] = carry[i] % 10;
}
memcpy(ans, carry, sizeof(ans));
}
void fun2(){
memset(carry, 0, sizeof(carry));
for(int i = 1;i <= 500;i++){
for(int j = 1;j <= 500;j++){
carry[i + j - 1] += b[i] * b[j];
}
}
for(int i = 1;i <= 500;i++){
carry[i + 1] += carry[i] / 10;
carry[i] = carry[i] % 10;
}
memcpy(b, carry, sizeof(b));
}
int main(){
int p;
cin >> p;
printf("%d\n", (int)( p * log10(2) ) + 1);
//賦初值
ans[1] = 1, b[1] = 2;
while(p){
if(p % 2){
fun1();
}
fun2();
p /= 2;
}
//題目要計算的是2 ^ {P} - 1
ans[1] -= 1;
for(int i = 500;i > 0;i--){
if(i != 500 && i % 50 == 0){
printf("\n%d", ans[i]);
}else{
printf("%d", ans[i]);
}
}
return 0;
}