【题解】【高精度】—— [NOIP2003 普及组] 麦森数
- [NOIP2003 普及组] 麦森数
- 题目描述
- 输入格式
- 输出格式
- 输入输出样例
- 输入 #1
- 输出 #1
- 提示
- 1.题意解析
- 1.1.求位数
- 1.2.输出最后500位
- 1.2.1.输出
- 1.2.2.高精度乘法
- 1.2.3.快速幂
- 2.AC代码
[NOIP2003 普及组] 麦森数
题目描述
形如 2 P − 1 2^{P}-1 2P−1 的素数称为麦森数,这时 P P P 一定也是个素数。但反过来不一定,即如果 P P P 是个素数, 2 P − 1 2^{P}-1 2P−1 不一定也是素数。到 1998 年底,人们已找到了 37 个麦森数。最大的一个是 P = 3021377 P=3021377 P=3021377,它有 909526 位。麦森数有许多重要应用,它与完全数密切相关。
任务:输入 P ( 1000 < P < 3100000 ) P(1000<P<3100000) P(1000<P<3100000),计算 2 P − 1 2^{P}-1 2P−1 的位数和最后 500 500 500 位数字(用十进制高精度数表示)
输入格式
文件中只包含一个整数 P ( 1000 < P < 3100000 ) P(1000<P<3100000) P(1000<P<3100000)
输出格式
第一行:十进制高精度数 2 P − 1 2^{P}-1 2P−1 的位数。
第 2 ∼ 11 2\sim 11 2∼11 行:十进制高精度数 2 P − 1 2^{P}-1 2P−1 的最后 500 500 500 位数字。(每行输出 50 50 50 位,共输出 10 10 10 行,不足 500 500 500 位时高位补 0 0 0)
不必验证 2 P − 1 2^{P}-1 2P−1 与 P P P 是否为素数。
输入输出样例
输入 #1
1279
输出 #1
386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087
提示
【题目来源】
NOIP 2003 普及组第四题
1.题意解析
我们把这道题分成两个模块。一个是求位数,另一个是输出最后500位。
1.1.求位数
我们知道,一个数 1 0 k > n > 1 0 k − 1 10^k>n>10^{k-1} 10k>n>10k−1,那么它的位数就是 k k k。
又因为
2
p
2^p
2p 的最后一位数永远不可能是0
,不可能-1
之后退位导致位数减少。所以我们将求
2
p
−
1
2^p-1
2p−1 的位数转换成求
2
p
2^p
2p 的位数。
接下来我们设 2 p 的位数 = k 2^p的位数=k 2p的位数=k,则有 1 0 k > 2 p > 1 0 k − 1 10^k>2^p>10^{k-1} 10k>2p>10k−1
将不等式变个形 k > l o g 10 ( 2 p ) > k − 1 k>log_{10}(2^p)>k-1 k>log10(2p)>k−1
l o g x ( n ) log_x(n) logx(n) 表示 x k = n x^k=n xk=n中的 k k k,不理解可以自己上网去了解一下对数相关知识。
再根据对数的运算法则,可以得出
k
>
p
×
l
o
g
10
(
2
)
>
k
−
1
k>p\times log_{10}(2)>k-1
k>p×log10(2)>k−1
那么
p
×
l
o
g
10
(
2
)
p\times log_{10}(2)
p×log10(2)向下取整就等于
k
−
1
k-1
k−1。所以int(p*log10(2)+1)
就是最终的答案。
1.2.输出最后500位
接下来就要用到高精度了。还是老样子,使用我在高精度算法解析和高精度赛场用模板分装的bigint
结构体。不过有两个地方要稍微改一下。
1.2.1.输出
这里由于只要求输出最后的500位。所以我们可以从1~500遍历输出。每输出50个数,即i%50==0
就输出一个换行。
friend void print(bigint x)//输出,和普通的输出高精度整数略有不同
{
for(int i=1;i<=500;i++)//这里只输出最后500位
{
cout<<x[501-i];//500-i+1的化简
if(i%50==0)cout<<endl;//每输出50位就输出一个换行
}
}
1.2.2.高精度乘法
这里只需要计算最后500
位。展开时也最多展开500+500
位。改进后的代码如下:
friend bigint operator*(bigint a,bigint b)//乘法,这里只计算最后500位
{
bigint c;
int lena=a.len,lenb=b.len;
for(int i=1;i<=min(lena,500);i++)//最多计算500位
for(int j=1;j<=min(lenb,500);j++)//同理
c[i+j-1]+=a[i]*b[j];
c.flatten(min(lena+lenb,1000));//最多展开500+500位
return c;
}
1.2.3.快速幂
对于计算 2 p 2^p 2p,我们可以使用快速幂。这里直接给出快速幂模版。如果还不知道快速幂,可以去洛谷P1226 【模板】快速幂练练手。
bigint qpow(bigint a,int p)//快速幂
{
if(p==1)return a;
if(p%2==0)return qpow(a*a,p/2);
return a*qpow(a,p-1);
}
2.AC代码
#include<bits/stdc++.h>
using namespace std;
struct bigint
{
int a[1010],len;
bigint(int x=0)
{
memset(a,0,sizeof(a));
if(x==0)
{
len=1;
return;
}
for(len=1;x;len++)
a[len]=x%10,x/=10;
len--;
}
void flatten(int L)
{
len=L;
for(int i=1;i<=len;i++)
{
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(!a[len])
len--;
}
int &operator[](int i)
{
return a[i];
}
friend void print(bigint x)//输出,和普通的输出高精度整数略有不同
{
for(int i=1;i<=500;i++)//这里只输出最后500位
{
cout<<x[501-i];//500-i+1的化简
if(i%50==0)cout<<endl;//每输出50位就输出一个换行
}
}
//这里无需重载+
friend bigint operator*(bigint a,bigint b)//乘法,这里只计算最后500位
{
bigint c;
int lena=a.len,lenb=b.len;
for(int i=1;i<=min(lena,500);i++)//最多计算500位
for(int j=1;j<=min(lenb,500);j++)//同理
c[i+j-1]+=a[i]*b[j];
c.flatten(min(lena+lenb,1000));//最多展开500+500位
return c;
}
};
bigint qpow(bigint a,int p)//快速幂
{
if(p==1)return a;
if(p%2==0)return qpow(a*a,p/2);
return a*qpow(a,p-1);
}
int main()
{
int p;
bigint a;
cin>>p;
cout<<int(p*log10(2)+1)<<endl;//输出位数
a=qpow(2,p);a[1]--;//计算2^p-1
print(a);//输出
return 0;
}
喜欢就订阅此专辑吧!
【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。
欢迎扫码关注蓝胖子编程教育