题目描述
形如2^{P}-12P−1的素数称为麦森数,这时PP一定也是个素数。但反过来不一定,即如果PP是个素数,2^{P}-12P−1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。
任务:从文件中输入PP(1000<P<31000001000<P<3100000),计算2^{P}-12P−1的位数和最后500位数字(用十进制高精度数表示)
输入格式
文件中只包含一个整数PP(1000<P<31000001000<P<3100000)
输出格式
第一行:十进制高精度数2^{P}-12P−1的位数。
第2-11行:十进制高精度数2^{P}-12P−1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
不必验证2^{P}-12P−1与PP是否为素数。
输入输出样例
输入 #1复制
1279
输出 #1复制
386 00000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000 00000000000000104079321946643990819252403273640855 38615262247266704805319112350403608059673360298012 23944173232418484242161395428100779138356624832346 49081399066056773207629241295093892203457731833496 61583550472959420547689811211693677147548478866962 50138443826029173234888531116082853841658502825560 46662248318909188018470682222031405210266984354887 32958028878050869736186900714720710555703168729087
分析:
这题拿到会认为就是简单地循环进行2的乘法,但如果仔细想想,随着p的增大,肯定会爆int, long long int也不行,不用多想了,所以肯定要进行高精度乘法,正好前几天写了个高精度乘法,拿来试试?
#include<iostream>
#include<string>
#include<vector>
#include<math.h>
using namespace std;
string add(string str1,string str2);
string mul(string str1,string str2);
string sub(string str1,string str2);
string calc();
int p;
int main()
{
cin>>p;
cout<<(int)(log10(2)*p+1)<<endl;
string ans=calc();
//cout<<ans<<endl;
int len=ans.size();
//cout<<len<<endl;
if(len<500)
{
for(int i=1;i<=500-len;i++)
ans='0'+ans;
}
int flag=1;
for(int i=0;i<=499;i++)
{
cout<<ans[i];
if((i+1)%50==0&&(i+1)!=500)
cout<<endl;
}
return 0;
}
string add(string str1,string str2)
{
if(str1.length()<str2.length())
{
string s;
s=str1;
str1=str2;
str2=s;
}
string str;
int len1=str1.length();
int len2=str2.length();
int dis=len1-len2;
int cf=0;
for(int i=len2-1;i>=0;i--)
{
int temp=str1[i+dis]-'0'+str2[i]-'0'+cf;
cf=temp/10;
temp=temp%10;
str=char(temp+'0')+str;
if(str.size()>500)
break;
//cout<<"cf is "<<cf<<" temp is "<<temp<<endl;
}
for(int i=dis-1;i>=0;i--)
{
int temp=str1[i]-'0'+cf;
cf=temp/10;
temp=temp%10;
str=char(temp+'0')+str;
}
if(cf>0)
str=char(cf+'0')+str;
if(str.find_first_not_of('0')==str.npos)
str="0";
else
str.erase(0,str.find_first_not_of('0'));
return str;
}
string mul(string str1,string str2)
{
if(str1.length()<str2.length())
{
string s;
s=str1;
str1=str2;
str2=s;
}
string str="0";
string tempstr;
int len1=str1.length();
int len2=str2.length();
int dis=len1-len2;
int cf=0;
for(int i=len2-1;i>=0;i--)
{
tempstr.clear();
cf=0;
for(int j=len1-1;j>=0;j--)
{
int temp=(str1[j]-'0')*(str2[i]-'0')+cf;
//cout<<"temp is "<<temp<<endl;
cf=temp/10;
//cout<<"cf is "<<cf<<endl;
temp=temp%10;
tempstr=char(temp+'0')+tempstr;
if(tempstr.size()>500)
break;
//cout<<endl;
}
if(cf>0)
tempstr=char(cf+'0')+tempstr;
for(int k=1;k<=len2-1-i;k++)
tempstr=tempstr+'0';
if(tempstr.find_first_not_of('0')==tempstr.npos)
tempstr="0";
else
tempstr.erase(0,tempstr.find_first_not_of('0'));
//cout<<"tempstr is "<<tempstr<<endl;
str=add(str,tempstr);
//cout<<"str is "<<str<<endl;
if(str.size()>500)
str.erase(str.begin(),str.end()-500);
}
if(str.find_first_not_of('0')==str.npos)
str="0";
else
str.erase(0,str.find_first_not_of('0'));
return str;
}
string calc()
{
//这一段的思路很简单,就是先进行2^1,2^2,2^4,2^8,2^16...2^2n
//直到接近p,然后再从2^1开始,进行剩下的p
string str="1";
string s1;
int lasti=2;
s1=char(2+'0')+s1;
int dis=p;
while(dis!=0)
{
s1.clear();
s1=char(2+'0')+s1;
if(dis==1)
{
str=mul(str,"2");
lasti--;
break;
}
for(int i=2;i<=dis;)
{
//string s2;
//s2=char(2+'0')+s2;
//s1=mul(s1,s2);
s1=mul(s1,s1);
//cout<<"i is "<<i<<" s1 is "<<s1<<endl;
if(s1.size()>500)
s1.erase(s1.begin(),s1.end()-500);
lasti=i;
i=2*i;
}
str=mul(str,s1);
dis=dis-lasti;
//cout<<"lasti is "<<lasti<<" dis is "<<dis<<endl;
//cout<<"str is "<<str<<endl;
}
str=sub(str,"1");
return str;
}
string sub(string str1,string str2)
{
if(str1.length()<str2.length())
{
string s;
s=str1;
str1=str2;
str2=s;
}
string str;
int len1=str1.length();
int len2=str2.length();
int dis=len1-len2;
int cf=0;
for(int i=len2-1;i>=0;i--)
{
if((str1[i+dis]-'0')>=(str2[i]-'0'+cf))
{
int temp=str1[i+dis]-'0'-(str2[i]-'0'+cf);
cf=0;
str=char(temp+'0')+str;
}
else
{
int temp=str1[i+dis]-'0'+10-(str2[i]-'0'+cf);
cf=1;
str=char(temp+'0')+str;
}
//cout<<"cf is "<<cf<<" temp is "<<temp<<endl;
}
for(int i=dis-1;i>=0;i--)
{
if(cf>0)
{
int temp=str1[i]-'0'+10-cf;
cf=1;
str=char(temp+'0')+str;
}
else
{
int temp=str1[i]-'0'-cf;
cf=0;
str=char(temp+'0')+str;
}
}
return str;
}
一运行,哎呀,60分,超时,这是咋回事,我也考虑了500之后的不管了呀,那去看看别人怎么写的
原来大家都在用快速幂,这寒假学的东西谁还记得,那没办法,复习一下,嗯,来试试
#include<iostream>
#include<string>
#include<vector>
#include<math.h>
using namespace std;
string add(string str1,string str2);
string mul(string str1,string str2);
string sub(string str1,string str2);
string calc();
int p;
int main()
{
cin>>p;
cout<<(int)(log10(2)*p+1)<<endl;
string ans=calc();
//cout<<ans<<endl;
int len=ans.size();
//cout<<len<<endl;
if(len<500)
{
for(int i=1;i<=500-len;i++)
ans='0'+ans;
}
int flag=1;
for(int i=0;i<=499;i++)
{
cout<<ans[i];
if((i+1)%50==0&&(i+1)!=500)
cout<<endl;
}
return 0;
}
string add(string str1,string str2)
{
if(str1.length()<str2.length())
{
string s;
s=str1;
str1=str2;
str2=s;
}
string str;
int len1=str1.length();
int len2=str2.length();
int dis=len1-len2;
int cf=0;
for(int i=len2-1;i>=0;i--)
{
int temp=str1[i+dis]-'0'+str2[i]-'0'+cf;
cf=temp/10;
temp=temp%10;
str=char(temp+'0')+str;
if(str.size()>500)
break;
//cout<<"cf is "<<cf<<" temp is "<<temp<<endl;
}
for(int i=dis-1;i>=0;i--)
{
int temp=str1[i]-'0'+cf;
cf=temp/10;
temp=temp%10;
str=char(temp+'0')+str;
}
if(cf>0)
str=char(cf+'0')+str;
if(str.find_first_not_of('0')==str.npos)
str="0";
else
str.erase(0,str.find_first_not_of('0'));
return str;
}
string mul(string str1,string str2)
{
if(str1.length()<str2.length())
{
string s;
s=str1;
str1=str2;
str2=s;
}
string str="0";
string tempstr;
int len1=str1.length();
int len2=str2.length();
int dis=len1-len2;
int cf=0;
for(int i=len2-1;i>=0;i--)
{
tempstr.clear();
cf=0;
for(int j=len1-1;j>=0;j--)
{
int temp=(str1[j]-'0')*(str2[i]-'0')+cf;
//cout<<"temp is "<<temp<<endl;
cf=temp/10;
//cout<<"cf is "<<cf<<endl;
temp=temp%10;
tempstr=char(temp+'0')+tempstr;
if(tempstr.size()>500)
break;
//cout<<endl;
}
if(cf>0)
tempstr=char(cf+'0')+tempstr;
for(int k=1;k<=len2-1-i;k++)
tempstr=tempstr+'0';
if(tempstr.find_first_not_of('0')==tempstr.npos)
tempstr="0";
else
tempstr.erase(0,tempstr.find_first_not_of('0'));
//cout<<"tempstr is "<<tempstr<<endl;
str=add(str,tempstr);
//cout<<"str is "<<str<<endl;
if(str.size()>500)
str.erase(str.begin(),str.end()-500);
}
if(str.find_first_not_of('0')==str.npos)
str="0";
else
str.erase(0,str.find_first_not_of('0'));
return str;
}
string calc()
{
string ans="1";
string base;
int k=p/20;
base="1048576";
while(k!=0)
{
if(k&1!=0)
ans=mul(ans,base);
if(ans.size()>500)
ans.erase(ans.begin(),ans.end()-500);
base=mul(base,base);
if(base.size()>500)
base.erase(base.begin(),base.end()-500);
k>>=1;
}
//cout<<"ans is "<<ans<<endl;
k=p%20;
for (int i=0; i<k; i++)
ans=mul(ans,"2");
ans=sub(ans,"1");
return ans;
}
string sub(string str1,string str2)
{
if(str1.length()<str2.length())
{
string s;
s=str1;
str1=str2;
str2=s;
}
string str;
int len1=str1.length();
int len2=str2.length();
int dis=len1-len2;
int cf=0;
for(int i=len2-1;i>=0;i--)
{
if((str1[i+dis]-'0')>=(str2[i]-'0'+cf))
{
int temp=str1[i+dis]-'0'-(str2[i]-'0'+cf);
cf=0;
str=char(temp+'0')+str;
}
else
{
int temp=str1[i+dis]-'0'+10-(str2[i]-'0'+cf);
cf=1;
str=char(temp+'0')+str;
}
//cout<<"cf is "<<cf<<" temp is "<<temp<<endl;
}
for(int i=dis-1;i>=0;i--)
{
if(cf>0)
{
int temp=str1[i]-'0'+10-cf;
cf=1;
str=char(temp+'0')+str;
}
else
{
int temp=str1[i]-'0'-cf;
cf=0;
str=char(temp+'0')+str;
}
}
return str;
}
走你,卧槽,又超时?,我用了快速幂了啊,再看看吧,原来别人还用了数据压缩,我也学学...
几小时过去了.....
这数据压缩怎么这么难,不学了,看看其他的,我就不信了
嗯,数据压缩,数据压缩,看不懂的快速幂,看不懂得其他方法....
这....算了,不看题解了,吃个饭后上csdn看看
嗯,数据压缩,数据压缩,看不懂的快速幂,看不懂得其他方法....
......
费了一个小时,终于找到篇看懂的,这才反应过来,为什么我的方法会超时了
同样是高精度乘法,我用的是string来存储,人家用的却是int数组,这一点给了我很大的启发,我之前一直认为高精只能用string,所以谢了这么多题,都是stringAC的,直到今天,超时让我明白了string虽然可以实现高精,但是char类型的转换等等会很浪费时间。但是用int数组就不一样了,int数组计算起来也很方便,其实懂得原理一切都好解释了,就是存个数而已,string和int数组没有区别,以后要注意了
上AC代码:
#include<iostream>
#include<math.h>
using namespace std;
int a[1005];
int p;
void mul(int a[],int x);
int main()
{
cin>>p;
cout<<(int)(log10(2)*p+1)<<endl;
int k;
a[1]=1;
k=p/20;
for(int i=1;i<=k;i++)
mul(a,1048576);
k=p%20;
for(int i=1;i<=k;i++)
mul(a,2);
a[1]-=1;
for(int i=10;i>=1;i--)
{
for(int j=50;j>=1;j--)
cout<<a[(i-1)*50+j];
cout<<endl;
}
return 0;
}
void mul(int a[],int x)
{
int cf=0;
for(int i=1;i<=500;i++)
{
int y=a[i]*x+cf;
a[i]=y%10;
cf=y/10;
}
return;
}