【noip2003】 麦森数
题目描述
形如2P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。
任务:从文件中输入P(1000<P<3100000),计算2P-1的位数和最后500位数字(用十进制高精度数表示)
输入
文件中只包含一个整数P(1000<P<3100000)
输出
第一行:十进制高精度数2P-1的位数。
第2-11行:十进制高精度数2P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
不必验证2P-1与P是否为素数。
样例输入
样例输出
题解
首先这道题得从数论的角度入手,平时我们估计一个十进制数x(x>0)的位数,往往潜在地使用了放缩法:
若10^k<=x<10^(k+1),则x有k+1位。而当x=2^p-1时,由于x的末位不为0,因此不存在借位现象,所以x的位数等于2^p的位数。
又假设10^k<=2^p<10^(k+1),此中的k,便等于[log10(2^p)]也就是int(log10(2^p))。
最后简单变换一下,第一问的答案便是int(p*log10(2))+1。
第二问若用高精加法,时间复杂度为O(n)。但常数过大,超时在所难免。
于是想到,要用快速幂高精。
只有一点不同,此处的快速幂是递归形式的。
当由递归得到2^(p/2)的值时,便可以通过2^p=2^(p/2)*2^(p/2)得到2^p的值,若p是奇数,2^p=2^(p/2)*2^(p/2)*2即可。
根据2^p=2^(p/2)*2^(p/2),由高精得到a=b*b; if(n%2==1)
根据2^p=2^(p/2)*2^(p/2)*2,由高精得到a=b*b*2;
处理a数组进位,更新b数组;
清空a数组;
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 long long p,a[10005]={0},b[10005]={0}; 8 void bigpow(long long n){ 9 if(n==0) return; 10 bigpow(n/2); 11 if(n%2==0){ 12 for(int i=1;i<=500;i++) 13 for(int j=1;j<=500;j++) 14 a[i+j-1]=a[i+j-1]+b[i]*b[j]; 15 } 16 if(n%2==1){ 17 for(int i=1;i<=500;i++) 18 for(int j=1;j<=500;j++) 19 a[i+j-1]=a[i+j-1]+b[i]*b[j]*2; 20 } 21 for(int i=1;i<=500;i++){ 22 b[i]=a[i]%10; 23 a[i+1]=a[i+1]+a[i]/10; 24 } 25 memset(a,0,sizeof(a)); 26 } 27 int main(){ 28 ios::sync_with_stdio(false); 29 cin>>p; 30 cout<<(int)(p*log10(2)+1)<<endl; 31 b[1]=1; 32 bigpow(p); 33 for(int i=500;i>1;i--){ 34 cout<<b[i]; 35 if(i%50==1) cout<<endl; 36 } 37 cout<<b[1]-1<<endl; 38 return 0; 39 }