题前建议
在做本题之前建议先学会高精度加法、快速幂、log函数的使用
题目描述
形如 −1的素数称为麦森数,这时 𝑃 一定也是个素数。但反过来不一定,即如果 𝑃 是个素数,−1不一定也是素数。到 1998 年底,人们已找到了 37 个麦森数。最大的一个是 𝑃=3021377,它有 909526 位。麦森数有许多重要应用,它与完全数密切相关。
任务:输入 𝑃(1000<𝑃<3100000),计算 −1 的位数和最后 500500 位数字(用十进制高精度数表示)
输入格式
文件中只包含一个整数 𝑃(1000<𝑃<3100000)
输出格式
第一行:十进制高精度数 −1 的位数。
第 2∼11 行:十进制高精度数 −1 的最后 500500 位数字。(每行输出 5050 位,共输出 1010 行,不足 500500 位时高位补 00)
不必验证 −1 与 𝑃 是否为素数。
输入输出样例
输入 #1
1279
输出 #1
386 00000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000 00000000000000104079321946643990819252403273640855 38615262247266704805319112350403608059673360298012 23944173232418484242161395428100779138356624832346 49081399066056773207629241295093892203457731833496 61583550472959420547689811211693677147548478866962 50138443826029173234888531116082853841658502825560 46662248318909188018470682222031405210266984354887 32958028878050869736186900714720710555703168729087
具体讲解
对于本题是一个高精度快速幂的问题,但中间需要一些技巧。
首先,高精度快速幂我就不讲了需要的同学可以看一下代码。
高精乘法:
vector<int> mul(vector<int> a,vector<int> b)
{
vector<int> c(a.size()+b.size()+1);
for(int i=0;i<a.size();++i)
{
for(int j=0;j<b.size();++j)
{
c[i+j]+=a[i]*b[j];
c[i+j+1]+=c[i+j]/10;
c[i+j]%=10;
}
}
while(c.size()>1 && c.back()==0) c.pop_back();
return c;
}//传入的a、b和返回的c皆为倒着的
快速幂:
int binpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
{
res*=a;
}
a=a*a;
b>>=1;
}
return res;
}
注意:本题的p(1000<𝑃<3100000),不用使用高精度。
将他俩结合:
vector<int> mul(vector<int> a,vector<int> b)
{
vector<int> c(a.size()+b.size()+1);
for(int i=0;i<a.size();++i)
{
for(int j=0;j<b.size();++j)
{
c[i+j]+=a[i]*b[j];
c[i+j+1]+=c[i+j]/10;
c[i+j]%=10;
}
}
while(c.size()>1 && c.back()==0) c.pop_back();
return c;
}
vector<int> qpow(vector<int> a,int b) {
vector<int> res;
res.push_back(1);
while(b)
{
if(b&1)
{
res=mul(res,a);
}
a=mul(a,a);
b>>=1;
}
return res;
}
由此小伙伴们应该可以写出一段暴力的50TLE代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<int> mul(vector<int> a,vector<int> b)
{
vector<int> c(a.size()+b.size()+1);
for(int i=0;i<a.size();++i)
{
for(int j=0;j<b.size();++j)
{
c[i+j]+=a[i]*b[j];
c[i+j+1]+=c[i+j]/10;
c[i+j]%=10;
}
}
while(c.size()>1 && c.back()==0) c.pop_back();
return c;
}
vector<int> qpow(vector<int> a,int b) {
vector<int> res;
res.push_back(1);
while(b)
{
if(b&1)
{
res=mul(res,a);
}
a=mul(a,a);
b>>=1;
}
return res;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int n;
vector<int> sum;
sum.push_back(2);
cin>>n;
sum=qpow(sum,n);
cout<<sum.size()<<"\n";
while(sum.size()<500)
{
sum.push_back(0ll);
}
for(int i=499;i>=0;--i)
{
if(i==0)
{
cout<<sum[0]-1;
return 0;
}
cout<<sum[i];
if((i)%50==0 && i!=499)
{
cout<<"\n";
}
}
return 0;
}
于是小伙伴们可以想到:最后只要输出500位但我们却因为长度多算了很多,所以我们可以使用计算机的log10/log函数简化一下:
如果使用log函数,大家要使用换底公式比较麻烦,所以建议使用log10函数可以方便一点,这样我们就可以写出AC代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
vector<int> mul(vector<int> a,vector<int> b)
{
vector<int> c(a.size()+b.size()+1);
for(int i=0;i<a.size();++i)
{
for(int j=0;j<b.size();++j)
{
c[i+j]+=a[i]*b[j];
c[i+j+1]+=c[i+j]/10;
c[i+j]%=10;
}
}
while(c.size()>1 && c.back()==0) c.pop_back();
return c;
}
vector<int> qpow(vector<int> a,int b) {
vector<int> res;
res.push_back(1);
while(b)
{
if(b&1)
{
res=mul(res,a);
}
a=mul(a,a);
b>>=1;
while(res.size()>500)
{
res.pop_back();
}
while(a.size()>500)
{
a.pop_back();
}
}
return res;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int n;
vector<int> sum;
sum.push_back(2);
cin>>n;
sum=qpow(sum,n);
cout<<(int)(log10(2)*n+1)<<"\n";//或cout<<(int)(log(2)*n/log(10))+1<<"\n";
while(sum.size()<500)
{
sum.push_back(0ll);
}
for(int i=499;i>=0;--i)
{
if(i==0)
{
cout<<sum[0]-1;
return 0;
}
cout<<sum[i];
if((i)%50==0 && i!=499)
{
cout<<"\n";
}
}
return 0;
}
好了今天这道比较综合的题目就OK了如果高精度不熟练的小伙伴们可以做一下:
洛谷 P1932 A+B A-B A*B A/B A%B Problem(A+B A-B A*B A/B A%B Problem - 洛谷)
goodbye😊😎