P1045 [NOIP2003 普及组] 麦森数

P1045 [NOIP2003 普及组] 麦森数

直接纯模拟,然后想办法优化

  • 如果直接模拟计算那么位数太大会超时数学方法
  • 一次乘2^20次方
  • 做题的时候想到的 (貌似叫做压位)

一般来说高精度原理,是把让数组的每一位表示数的位数,所以只要第一位大于10,就直接进位

如果每一次都这样进位的话,那么时间的开销会很大

那么就可以考虑当第一个数为10位数时再进位;这样会大大减少时间

注意细节

  • 没有满500位需要输出前导零
  • 其实如果长度大于500,就不需要再多计算,只需要计算500以内的数(也是种减少时间的方法
  • 高精(压位)完之后 再高精一次,这时的高精需要按照十进制再进位(这里也就最大O(500))
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int p;
long long s[520];
int main(){
    bool book=0;
    scanf("%d",&p);
    memset(s,0,sizeof(s));
    s[1]=1;
    int len=1;
    int lim=p/20;
    for(register int i=1;i<=lim;++i){//一次2^20次方
        for(register int j=1;j<=len;++j)
            s[j]*=1048576;//2的20次方 
        if(s[1]>=10000000000){
            for(register int k=1;k<=len;++k)
                if(s[k]>=10){
                    if(len==500)
                        book=1;
                    s[k+1]+=s[k]/10;
                    s[k]%=10;
                    if(s[len+1]!=0 && book==0) ++len;
                }
        }
    }
    if(p%20!=0){//还有不满20的次数就一个一个*
        for(register int i=1;i<=p%20;++i){
            for(register int j=1;j<=len;++j)
                s[j]*=2;
                if(s[1]>=10000000000){//压位
                for(register int k=1;k<=len;++k)
                    if(s[k]>=10){
                    if(len==500)
                        book=1;
                    s[k+1]+=s[k]/10;
                    s[k]%=10;
                    if(s[len+1]!=0 && book==0) ++len;
                }
            }
        }
    }
    for(register int k=1;k<=len;++k)//十进制高精
            if(s[k]>=10){
                if(len==500)
                    book=1;
                s[k+1]+=s[k]/10;
                s[k]%=10;
                if(s[len+1]!=0 && book==0) ++len;
            }
    s[1]-=1;
    int ans=(int)p*log10(2)+1;//位数

    printf("%d\n",ans);
    if(ans<500){
        register int j=1;
        for(register int i=ans+1;i<=500;++i,++j){
            printf("0");
            if(j%50==0) printf("\n");
        }
        for(register int i=ans;i>=1;--i,++j){
                printf("%lld",s[i]);
            if(j%50==0) printf("\n");
        }
    }
    else{
            for(register int i=500,j=1;i>=1;--i,++j){
                printf("%lld",s[i]);
                if(j%50==0)printf("\n");
            }   
    }
   //输出
    return 0;
}
posted @ 2021-02-18 20:58  归游  阅读(57)  评论(0编辑  收藏  举报