蓝桥杯 算法训练 麦森数(快速幂算法)

问题描述
  形如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的位数。
  第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;
}



猜你喜欢

转载自blog.csdn.net/langzitan123/article/details/80222289