问题描述
形如2
P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2
P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。
任务:从文件中输入P(1000<P<3100000),计算2 P-1的位数和最后500位数字(用十进制高精度数表示)
任务:从文件中输入P(1000<P<3100000),计算2 P-1的位数和最后500位数字(用十进制高精度数表示)
输入格式
文件中只包含一个整数P(1000<P<3100000)
输出格式
第一行:十进制高精度数2
P-1的位数。
第2-11行:十进制高精度数2 P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
不必验证2 P-1与P是否为素数。
第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
首先,我们可以用log10函数直接求出一个整数的位数,我们只需将给出的指数形式的数根据对数公式稍作变换即可。接下来只需面对结果的最后五百位这个问题。
很显然,直接将p个2相乘的话是会超时的,这里介绍一种快速幂算法,基于二分算法的一种衍生算法。
我们要计算一个数的幂时,先将它的指数进行二分,直至分到无法再分,然后计算时用这个数自己乘自己代替不断乘2,可以大大减少使用乘法的次数,当然要注意二分的过程是否有余数,如果有的话不要忘记乘进去。本题代码如下:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<cmath>
#define Inf 99999999
using namespace std;
void cheng_er(int *num)
{
int jinwei=0;
for(int i=499;i>=0;i--)
{
num[i]=num[i]*2+jinwei;
if(num[i]>9)
{num[i]-=10;
jinwei=1;}
else
jinwei=0;
}
}
void cheng(int *a,int *b)
{
int c[500];
memset(c,0,sizeof(c));
int k;
for(int i=499;i>=0;i--)
{ k=i;
for(int j=499;j>=0;j--)
{
c[k]+=a[i]*b[j];
if(k==0)
break;
k--;
}
}
for(int i=499;i>=1;i--)
{
if(c[i]>9)
{c[i-1]+=c[i]/10;
c[i]=c[i]%10;}
a[i]=c[i];
}
c[0]=c[0]%10;
a[0]=c[0];
}
void quick_pow(int *num,int n)
{
if(n==1)
{num[499]*=2;
return;}
quick_pow(num,n/2); //对幂不断进行二分
cheng(num,num); //二分后用自身乘法代替不断乘底数
if(n%2!=0) //当幂是奇数时,在它二分自身乘法的基础上还要再乘一个底数
cheng_er(num);
}
int main()
{
int num[500];
memset(num,0,sizeof(num));
int n;
num[499]=1;
scanf("%d",&n);
printf("%d\n",int(n*log10(2))+1);
quick_pow(num,n);
int c=499;
while(num[c]==0)
{num[c]=9;
c--;}
num[c]--;
for(int i=0;i<500;i++)
{
printf("%d",num[i]);
if(i%50==49)
printf("\n");
}
return 0;
}
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087
首先,我们可以用log10函数直接求出一个整数的位数,我们只需将给出的指数形式的数根据对数公式稍作变换即可。接下来只需面对结果的最后五百位这个问题。
很显然,直接将p个2相乘的话是会超时的,这里介绍一种快速幂算法,基于二分算法的一种衍生算法。
我们要计算一个数的幂时,先将它的指数进行二分,直至分到无法再分,然后计算时用这个数自己乘自己代替不断乘2,可以大大减少使用乘法的次数,当然要注意二分的过程是否有余数,如果有的话不要忘记乘进去。本题代码如下:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<cmath>
#define Inf 99999999
using namespace std;
void cheng_er(int *num)
{
int jinwei=0;
for(int i=499;i>=0;i--)
{
num[i]=num[i]*2+jinwei;
if(num[i]>9)
{num[i]-=10;
jinwei=1;}
else
jinwei=0;
}
}
void cheng(int *a,int *b)
{
int c[500];
memset(c,0,sizeof(c));
int k;
for(int i=499;i>=0;i--)
{ k=i;
for(int j=499;j>=0;j--)
{
c[k]+=a[i]*b[j];
if(k==0)
break;
k--;
}
}
for(int i=499;i>=1;i--)
{
if(c[i]>9)
{c[i-1]+=c[i]/10;
c[i]=c[i]%10;}
a[i]=c[i];
}
c[0]=c[0]%10;
a[0]=c[0];
}
void quick_pow(int *num,int n)
{
if(n==1)
{num[499]*=2;
return;}
quick_pow(num,n/2); //对幂不断进行二分
cheng(num,num); //二分后用自身乘法代替不断乘底数
if(n%2!=0) //当幂是奇数时,在它二分自身乘法的基础上还要再乘一个底数
cheng_er(num);
}
int main()
{
int num[500];
memset(num,0,sizeof(num));
int n;
num[499]=1;
scanf("%d",&n);
printf("%d\n",int(n*log10(2))+1);
quick_pow(num,n);
int c=499;
while(num[c]==0)
{num[c]=9;
c--;}
num[c]--;
for(int i=0;i<500;i++)
{
printf("%d",num[i]);
if(i%50==49)
printf("\n");
}
return 0;
}