【高精度】麦森数 NOIP 2003

[NOIP2003]麦森数

 

时间限制: 1 Sec  内存限制:64 MB

 

题目描述

形如2^p-1的素数称为麦森数,这时p一定也是个素数。但反过来不一定,即如果p是个素数,2^p-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是p=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。现要求输入p(1000< P < 3100000),计算2^p-1的位数和最后500位数字(用十进制高精度数表示)。

输入

第1行:1个整数p(1000

输出

第1行:十进制高精度数2^p-1的位数;第2..11行:十进制高精度数2^p-1的最后500位数字(每行输出50位,共输出10行,不足500位时高位补0); 注意:不必验证2^p-1与p是否为素数。

样例输入

(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

1279

样例输出

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087 

刚开始看到这么一大堆(tuÓ)输出,其实我是拒绝的。

想了想,第一,高精度;第二,求p次幂要用快速幂(了解快速幂详见点这里!!)。

一、首先我们要知道怎么存500位的数,那么就存在一个结构体数组里面,进行高精度乘法的时候,就可以想一想竖式是怎么计算的。但是想一想竖式是从最低位开始乘起来的,所以我用的数组是倒序存数,最后输出只要倒回来输出就行了。

这里用到了重载运算符:

big operator *(big &ys)const
	{big ans;
		
		for(int i=1;i<=len;i++)
			for(int j=1;j<=ys.len;j++)
			{
				if(i+j-1>500) break;//如果位数>500,不用考虑
				ans.A[i+j-1]+=A[i]*ys.A[j];//为什么是i+j-1,
                                                           //自己想想竖式计算
                                if(ans.A[i+j-1]>=10)//向后进位
				{
					ans.A[i+j]+=ans.A[i+j-1]/10;
					ans.A[i+j-1]%=10;
				}
			}
		for(int i=500;i>=1;i--)//求位数
                        if(ans.A[i]!=0){ans.len=i;break;}
                return ans;
	}

二、进行幂运算的时候,要把p进行二进制划分(自己看上面的链接)。

三、代码如下:

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;

int p;

struct big
{
	int A[501],len;//A存数,len存位数
	big(){memset(A,0,sizeof A);len=0;}//清0
	big operator *(big &ys)const//重载乘号
	{big ans;
		
		for(int i=1;i<=len;i++)
			for(int j=1;j<=ys.len;j++)
			{
				if(i+j-1>500) break;
				ans.A[i+j-1]+=A[i]*ys.A[j];
				if(ans.A[i+j-1]>=10)
				{
					ans.A[i+j]+=ans.A[i+j-1]/10;
					ans.A[i+j-1]%=10;
				}
			}
		for(int i=500;i>=1;i--)
			if(ans.A[i]!=0){ans.len=i;break;}
		return ans;
	}
}danwei,ans;


int main()
{
	scanf("%d",&p);
	danwei.A[1]=2;danwei.len=1;//danwei即使底数
	ans.A[1]=1;ans.len=1;
	printf("%d\n",int(p*log10(2))+1);
	while(p)//快速幂
	{
		if(p&1) ans=ans*danwei;
		p/=2;
		danwei=danwei*danwei;
	}
	ans.A[1]--;//求的是2^p-1,所以最后--
	for(int i=1;i<=10;i++)
	{
		for(int j=1;j<=50;j++)
			printf("%d",ans.A[501-(i-1)*50-j]);//倒序输出
		printf("\n");
	}
	
}

 

posted @ 2019-12-14 14:52  _Ark  阅读(155)  评论(0编辑  收藏  举报