【高精度】麦森数 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");
}
}