麦森数(大数)

麦森数

题目描述

形如2P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。 

任务:从文件中输入P(1000<P<3100000),计算2P-1的位数和最后500位数字(用十进制高精度数表示)。 


 

输入

每组输入只包含一个整数P(1000<P<3100000)。 

 

输出

第一行:十进制高精度数2P-1的位数。 

第2-11行:十进制高精度数2P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0) 

不必验证2P-1与P是否为素数。 


 

样例输入 Copy

1279

样例输出 Copy

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

来源/分类

2003年NOIP全国联赛普及组  

题解:题目要求只让求后500位的数字,所以我们就开一个500的数组,前边的数不用管。比赛时主要卡在两个点上

1、我们用大数写的求的是所有的位数,但因为数据太大,所以超时

2、后来我们限制了一下只计算后500位,但我们不会求2的n次方的位数,这其实就是一个公式n*(log2)+1

#include<cstdio>
#include<cstring>
#include<math.h>
#include<iostream>
#include<iomanip>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;

#define debug(x) printf("%d***\n",x)
#define ll long long
#define maxn 100000
#define inf 0x3f3f3f3f
#define mod 1000000007
const double pi=acos(-1.0);


string sum(string s1,string s2)    //大数加法
{
    if(s1.length()<s2.length())
    {
        string temp=s1;
        s1=s2;
        s2=temp;
    }
    int i,j;
    for(i=s1.length()-1,j=s2.length()-1; i>=0; i--,j--)
    {
        s1[i]=char(s1[i]+(j>=0?s2[j]-'0':0));
        if(s1[i]-'0'>=10)
        {
            s1[i]=char((s1[i]-'0')%10+'0');
            if(i) s1[i-1]++;
            else s1='1'+s1;
        }
    }
    return s1;
}

string mult(string s,int x)
{
    reverse(s.begin(),s.end());
    int cmp=0;
    int cccc=0;
    int dddd=s.size()-500;
    for(int i=max(cccc,dddd); i<s.size(); i++)
    {
        cmp=(s[i]-'0')*x+cmp;
        s[i]=(cmp%10+'0');
        cmp/=10;
    }
    while(cmp)
    {
        s+=(cmp%10+'0');
        cmp/=10;
    }
    reverse(s.begin(),s.end());
    return s;
}

string multfa(string x,string y)
{
    string ans;
    int cnt=500;
    int llll=y.size()-1;
    for(int i=min(cnt,llll),j=0; i>=0; i--,j++)
    {
        string tmp=mult(x,y[i]-'0');
        for(int k=0; k<j; k++)
            tmp+='0';
        ans=sum(ans,tmp);
    }
    return ans;
}

string subinfo(string s1,string s2)
{
    int a[maxn],b[maxn];
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    int l1=s1.size(),l2=s2.size();
    int maxl=max(l1,l2);
    for(int i=0; i<l1; i++)
        a[i]=s1[l1-i-1]-'0';
    for(int i=0; i<l2; i++)
        b[i]=s2[l2-i-1]-'0';
    for(int i=0; i<maxl; i++)
    {
        if(a[i]-b[i]<0)
        {
            a[i]=a[i]+10-b[i];
            a[i+1]-=1;
        }
        else a[i]-=b[i];
    }
    string str="";
    int i;
    for(i=maxl-1; i>=0; i--)
        if(a[i]!=0) break;
    for(; i>=0; i--) str+=a[i]+'0';
    return str;
}

string bigsub(string s1,string s2)
{
    if(s1==s2)
        return "0";
    int l1=s1.size(),l2=s2.size();
    if(l1>l2)
        return subinfo(s1,s2);
    else if(l1<l2)
        return "-"+subinfo(s2,s1);
    else
    {
        for(int i=0; i<l1; i++)
        {
            if(s1[i]-'0'>s2[i]-'0')
                return subinfo(s1,s2);
            else if(s1[i]-'0'<s2[i]-'0');
            return "-"+subinfo(s2,s1);
        }
    }

}

string powmi(string a,int b)
{
    string ans="1";
    while(b)
    {
        if(b%2==1)
            ans=multfa(ans,a);
        a=multfa(a,a);
        b/=2;
    }
    return ans;
}

int main()
{
    string a,ans1,p;
    int b;
    p="1";
    a="2";
    while(cin>>b)
    {
        ans1=bigsub(powmi(a,b),p);

        int l=(int)(b*log10(2)+1);
        cout<<l<<endl;
        int kk=500-l;
        int s=0;
        if(kk>0)
        {
            for(int i=0; i<kk; i++,s++)
            {
                if(s==50)
                {
                    s=0;
                    cout<<endl;
                }
                cout<<"0";
            }
        }
        for(int i=max(l-500,0); i<l; i++,s++)
        {
            if(s==50)
            {
                s=0;
                cout<<endl;
            }
            cout<<ans1[i];
        }
        cout<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值