洛谷-P1045 麦森数

题目描述

形如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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值