006.高精度快速幂

P1045 [NOIP 2003 普及组] 麦森数

题目链接

题目描述

形如 \(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\sim 11\) 行:十进制高精度数 \(2^{P}-1\) 的最后 \(500\) 位数字。(每行输出 \(50\) 位,共输出 \(10\) 行,不足 \(500\) 位时高位补 \(0\)

不必验证 \(2^{P}-1\)\(P\) 是否为素数。

输入输出样例 #1

输入 #1

1279

输出 #1

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

说明/提示

【题目来源】
NOIP 2003 普及组第四题

思路

数学方法计算位数

位数=p*log10(2)+1

int p;
read(p);
int len=p*log10(2)+1;
wr2(len);
//设置位数
SIZE=max(500,len)+5;

乘法只处理后500位

void BigMulBig(int a[],int b[],int c[]){
  memset(c,0,sizeof(int)*SIZE);
  for(int i=1;i<=a[0]&&i<=500;++i){//超过500的不处理
    int ex=0;
    for(int j=1;j<=b[0]&&i+j-1<=500;++j){//超过500的不处理
      c[i+j-1]=c[i+j-1]+a[i]*b[j]+ex;
      ex=c[i+j-1]/10;
      c[i+j-1]%=10;
    }
    int k=i+b[0];
    while(ex&&k<=500){//超过500的不处理
      c[k]+=ex;
      ex=c[k]/10;
      c[k]%=10;
      k++;
    }
  }
    int n=a[0]+b[0];
    while(c[n]==0&&n>1)n--;
    c[0]=n;
}

快速幂计算2^p

//初始化 a 为 1
// a[SIZE]= {0} , a[0]=a[1]=1;
void qp(int a[],int p){
  int b[SIZE],temp[SIZE];
  b[0]=1,b[1]=2;
  while(p){
    if(p&1){
      BigMulBig(a,b,temp);
      memcpy(a,temp,sizeof(temp));
    }
    BigMulBig(b,b,temp);
    memcpy(b,temp,sizeof(temp));
    p>>=1;
  }
}
//得到 a = 2^p

减一 ( 比较丑陋 )

//偷懒直接用模板
// b[SIZE]={0},b[0]=b[1]=1
void BigSub2(int a[],int b[]){
    int i=1;
    while(i<=b[0]){
        if(a[i]<b[i]){
            int j=i+1;
            while(j<=a[0]&&a[j]==0)a[j++]=9;
            a[j]--;
            a[i]+=10;
        }
        a[i]-=b[i];
        i++;
    }
    while(i<=a[0]&&a[i]<0){
        a[i]+=10;
        a[i+1]--;
        i++;
    }
    while(a[0]>1&&a[a[0]]==0)a[0]--;
}
//得到  a-1

code

#include<bits/stdc++.h>
using namespace std;
namespace IO{template<typename type>inline void read(type &x){x=0;int f=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}f?x=-x:0;}template<typename type>inline void wr(type x){x<0?x=-x,putchar('-'):0;static short stk[50],top(0);do stk[++top]=x%10,x/=10;while(x);while(top)putchar(stk[top--]+'0');}template<typename type>inline void wr1(type x){wr(x),putchar(' ');}template<typename type>inline void wr2(type x){wr(x),putchar('\n');}inline void readline(char *s){char ch=getchar();int i(0);while(ch=='\n'||ch=='\r')ch=getchar();while(ch!='\n'&&ch!='\r'&&ch!=EOF)s[i++]=ch,ch=getchar();s[i]='\0';}inline void write(const char*s){while(*s)putchar(*s++);}inline void writeline(const char*s){write(s),putchar('\n');}}using namespace IO;

int SIZE;//待定

void BigRead(int a[]){char s[SIZE];scanf("%s",s);int n=strlen(s);memset(a,0,sizeof(int)*SIZE);a[0]=n;for(int i=n;i;--i)a[i]=s[n-i]-'0';}
void BigWrite(int a[]){for(int i=a[0];i;i--)putchar(a[i]+'0');}
void BigSub2(int a[],int b[]){int i=1;while(i<=b[0]){if(a[i]<b[i]){int j=i+1;while(j<=a[0]&&a[j]==0)a[j++]=9;a[j]--;a[i]+=10;}a[i]-=b[i];i++;}while (i<=a[0]&&a[i]<0){a[i]+=10;a[i+1]--;i++;}while(a[0]>1&&a[a[0]]==0)a[0]--;}
void BigMulBig(int a[],int b[],int c[]){
  memset(c,0,sizeof(int)*SIZE);
  for(int i=1;i<=a[0]&&i<=500;++i){
    int ex=0;
    for(int j=1;j<=b[0]&&i+j-1<=500;++j){
      c[i+j-1]=c[i+j-1]+a[i]*b[j]+ex;
      ex=c[i+j-1]/10;
      c[i+j-1]%=10;
    }
    int k=i+b[0];
    while(ex&&k<=500){
      c[k]+=ex;
      ex=c[k]/10;
      c[k]%=10;
      k++;
    }
  }
    int n=a[0]+b[0];
    while(c[n]==0&&n>1)n--;
    c[0]=n;
}
void qp(int a[],int p){
  int b[SIZE],temp[SIZE];
  b[0]=1,b[1]=2;
  while(p){
    if(p&1){
      BigMulBig(a,b,temp);
      memcpy(a,temp,sizeof(temp));
    }
    BigMulBig(b,b,temp);
    memcpy(b,temp,sizeof(temp));
    p>>=1;
  }
}
int main(){
    int p;read(p);
    int len=p*log10(2)+1;
    wr2(len);
    SIZE=max(500,len)+5;
    int a[SIZE]={0};
    a[0]=a[1]=1;
    qp(a,p);
    int b[SIZE]={0};
    b[0]=b[1]=1;
    BigSub2(a,b);
    int t=500;
    for(int i=0;i<10;++i){
      for(int j=0;j<50;++j){
        wr(a[t--]);
      }
      putchar('\n');
    }
}
posted @ 2025-12-11 11:41  射杀百头  阅读(10)  评论(0)    收藏  举报