[NOIP2003 普及组] 麦森数

题目描述

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

任务:输入 P(1000<P<3100000)P(1000<P<3100000),计算 2^{P}-12P−1 的位数和最后 500500 位数字(用十进制高精度数表示)

输入格式

文件中只包含一个整数 P(1000<P<3100000)P(1000<P<3100000)

输出格式

第一行:十进制高精度数 2^{P}-12P−1 的位数。

第 2\sim 112∼11 行:十进制高精度数 2^{P}-12P−1 的最后 500500 位数字。(每行输出 5050 位,共输出 1010 行,不足 500500 位时高位补 00)

不必验证 2^{P}-12P−1 与 PP 是否为素数。

输入输出样例

输入 #1复制

1279

输出 #1复制

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

说明/提示

【题目来源】

NOIP 2003 普及组第四题

 

这道题纯粹是考数学。编程复杂度不大(别看我写了一百多行其实有些是可以不必写的)。

计算位数不必用高精时刻存,不然可想而知时间复杂度之大。首先大家要知道一个数学公式 logn(a*b)=logn(a)+logn(b)至于证明翻数学书吧。而且,用log10(n)+1即可求出n的位数。则2^p的位数=log10(2^p)+1=p*log10(2)+1。这样,我们算的时候就不必随时存着位数了。

但是,如果直接写高精和n次循环,时间复杂度依旧很高。所以我们就要用快速幂。幂的运算是初中内容,几个公式如下:n^a*n^b=n^(a+b),(n^a)^b=n^(a*b)。

所以,我们就可以将乘方的复杂度优化成O(logn)了。

             1(n==0),
             m(n==1),
f(m,n)=  f(m,n/2)^2(n%2==0),
             f(m,n/2)^2*m(n%2==1).

于是,时间复杂度就优化了不少。

#include<bits/stdc++.h>
using namespace std;

struct Hint {
    static const int MAX=4000;
    short a[MAX+1];
    int Len;
    Hint() {
        memset(a,0,sizeof(a));
        Len=1;
    }

    Hint operator=(std::string N) {
        memset(a,0,sizeof(a));
        if(N[0]=='-') {
            Len=N.size()-1;
            a[0]=1;
            for(int i=1; i<=Len; ++i)
                a[i]=N[Len-i+1]-'0';
            return *this;
        }
        if(N[0]=='+') {
            Len=N.size()-1;
            a[0]=0;
            for(int i=1; i<=Len; ++i)
                a[i]=N[Len-i+1]-'0';
            return *this;
        }
        Len=N.size();
        for(int i=1; i<=Len; ++i)
            a[i]=N[Len-i]-'0';
        return *this;
    }

    Hint operator=(const int & b) {
        char s[MAX+1];
        sprintf(s,"%d",b);
        *this=s;
        return *this;
    }

    Hint(std::string N) {
        *this=N;
    }
    Hint(const int &b) {
        *this=b;
    }

    int read() {
        char s[MAX+1];
        int t=scanf("%s",s);
        *this=s;
        return t;
    }

    void write() {
        int r,re=1,now=0;
        for(int i=Len; i>=1; --i) {
            cout<<a[i];
            ++now;
            if(now%50==0)cout<<endl;
        }    
    }
    Hint operator*(Hint x) {
        Hint c;
        c.Len=Len+x.Len;
        for(int i=1; i<=Len; ++i) {
            for(int j=1; j<=x.Len; ++j) {
                c.a[i+j-1]+=a[i]*x.a[j];
                if(c.a[i+j-1]>=10) {
                    c.a[i+j]+=c.a[i+j-1]/10;
                    c.a[i+j-1]%=10;
                }
            }
        }
        c.Len=500;
        return c;
    }

}two,ans;

int p;

Hint quick_power(int y)
{
    if(y==1)return two;
    if(y==0)return 1;
    Hint re;
    if(y%2==0)
    {
        re=quick_power(y/2);
        re=re*re;
    }
    else
    {
        re=quick_power(y/2);
        re=re*re*two;
    }
    return re;
}

int main()
{
    two=2;
    cin>>p;
    cout<<(long long)(log10(2)*p+1)<<endl;
    ans=quick_power(p);
    ans.a[1]-=1;
    ans.write();
    return 0;
}
```cpp

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值