题目链接:
https://www.luogu.org/problemnew/show/P1045
题意:
输入格式:
文件中只包含一个整数P(1000<P<3100000)
输出格式:
第一行:十进制高精度数2^P−1的位数。
第2-11行:十进制高精度数2^P−1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
不必验证2^P−1与P是否为素数。
题解:
1、首先需要输出位数,这里给大家推导一个公式可以直接计算2^n的位数(同样也可以计算n^k的位数)
先给出公式:的位数就是
+ 1
证明:
10 ^ <=
<= 10 ^
, 所以
的位数是:
+ 1
再举个通俗栗子:10 ^ 3 < 10 ^ 3.5 < 10^4,10的四次方是5位数(10000),10^3.5 次方小于 10000,且大于1000 所以是四位数,也就是 3.5取下整加 1 .
知道 怎么求位数了,那就把
转化为
的形式:
所以的位数就是
+ 1
所以的位数就是
+ 1
2、其次需要利用高精度进行模运算和取余数的工作,如代码所示:
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define MAXN ((int)1e5 + 10)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int a[2600];
int b[2600];
int r[2600];
void mul(int *a, int *b)
{
memset(r, 0, sizeof(r));
for(int i = 0; i < 500; i++){
int before = 0; //进的位数
for(int j = 0; j < 500; j++){
r[i + j] += a[i] * b[j] + before; // 通过 i + j 模拟乘法到了第几位了,从左到右存
before = r[i + j] / 10; //进位
r[i + j] = r[i + j] % 10;
}
if(before) r[i + 500] += before;//最后如果还有就把最后需要进的位加上
}
}
void power(int p)
{
memset(b, 0, sizeof(b));
b[0] = 2;//底数
while(p)
{
if(p & 1){
mul(a, b);
for(int i = 0; i < 500; i++) a[i] = r[i]; // 取余数
}
mul(b, b);
for(int i = 0; i < 500; i++) b[i] = r[i];// 取余数
p = p >> 1;
}
}
int main()
{
int p; cin>>p;
a[0] = 1; //初始化为 1
power(p);
a[0]--;// 2^p - 1 减的那个1
cout<<(int)(p*log10(2)+1)<<'\n';
for(int i = 499; i >= 0; i--){
printf("%d", a[i]);
if(i % 50 == 0) puts("");
}
}