蓝桥杯 ALGO-26 麦森数 (快速幂和高精度乘法)

## 题目如下:
  形如2P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。
  任务:从文件中输入P(1000<P<3100000),计算2P-1的位数和最后500位数字(用十进制高精度数表示)
【输入形式】
 文件中只包含一个整数P(1000<P<3100000)
【输出形式】
第一行:十进制高精度数2P-1的位数。
  第2-11行:十进制高精度数2P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
  不必验证2P-1与P是否为素数。
【样例输入】

1279

【样例输出】

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

解题思路:
首先解决2 ^p - 1的位数,这个比较简单,举个例子,一个4位数的范围在1000~9999,而log10(1000) = 3,log10(10000) = 4,也就是说如果一个数4位数a处于1000和10000之间,log10(a)取整后再加1就是a的位数了。所以2 ^ p - 1的位数就是[log10(2 ^p - 1)] +1,近似为int(p*log10(2)) + 1。

然后是2 ^p - 1的最后500位数,这里要用到快速幂算法和高精度乘法。

快速幂算法,我的理解就是幂次减半,底数平方,每当幂次为奇数时,在现在的结果上乘以底数。具体可以参考此博文:快速幂算法(全网最详细地带你从零开始一步一步优化)

高精度乘法,就是模拟我们笔算竖式乘法的过程。将两个乘数用整数数组储存,结果也用整数数组储存。具体可以参考此博文:浅谈高精度算法(加减乘除)

然后就是代码啦:

#include<iostream>
#include<cmath>
using namespace std;
void high_accuracy(int result[], int base[]) {
    
    //高精度乘法
	int w,num[1000] = {
    
    0};//num为中间储存乘法结果的数组。
	for(int i = 0 ; i < 500;i++)
		for (int j = 0; j < 500;j++) {
    
    
			w = base[i] * result[j];//模拟做竖式乘法的过程
			if (num[i + j] + w < 10) num[i + j] += w;//如果i+j位上的数加上w后仍然小于10,直接加上w就好了
			else {
    
    //否则的话要处理进位,将进位给i+j+1位,将本位留下来
				num[i + j + 1] += (num[i + j] + w) / 10;
				num[i + j] = (num[i + j] + w) % 10;
			}
		}

	for (int i = 0; i < 500;i++)//将结果更新给result
		result[i] = num[i];
	}

}

void fastpower(int p,int result[]){
    
    //快速幂
	int base[500] = {
    
     0 };
	base[0] = 2,result[0] = 1;
	while (p > 0) {
    
    
		if (p % 2 == 1) {
    
    //如果为奇次幂,就在当前的结果result的基础上乘底base(使用高精度乘法)
			high_accuracy(result, base);//result*base的高精度方法
		}
		p /= 2;//幂次减半
		high_accuracy(base, base);//幂次减半,底数平方,base*base的高精度方法
	 }

}

int main() {
    
    
	int p, Mersenne_digit,result[500] = {
    
     0 };
	cin >> p;
	Mersenne_digit = int(p*log10(2))+1;//麦森数的位数为:[log10(2^p -1)]+1
	cout << Mersenne_digit;
	fastpower(p,result);
	result[0] -= 1;
	for (int i = 500; i > 0; i--) {
    
    
		if (i % 50 == 0)
			cout << endl;
		cout << result[i-1];
	}
	return 0;
}

运行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/sgsx11/article/details/114765431