洛谷OJ P1045 麦森数 解题报告
洛谷OJ P1045 麦森数 解题报告
by MedalPluS
题目描述
形如2P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。
任务:从文件中输入P(1000<P<3100000),计算2P-1的位数和最后500位数字(用十进制高精度数表示)
输入描述
文件中只包含一个整数P(1000<P<3100000)
输出描述
第一行:十进制高精度数2^P-1的位数。
第2-11行:十进制高精度数2^P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
不必验证2^P-1与P是否为素数。
分析
首先2p-1的位数可以通过换底公式得到,即log102p+1 通过换底公式可以转换为log2/log10*p+1
然后就是高精度的过程
但注意,直接模拟的话会TLE,想一想为什么?因为直接模拟的复杂度应为500*500*3100000简直就是天文数字。。
那么怎么优化呢?
1.FFT优化高精度乘法,即降至500*8*3100000还是有TLE的风险
2.快速幂优化求幂,即降至500*8*19完全可以无压力AC
加上FFT代码太长,这里不贴了。。但不过只用快速幂是可以AC的
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 using namespace std; 5 6 const int maxn=50001; 7 8 //求2^p-1 高精度乘法&高-单 &快速幂 9 10 int ans[maxn],a[maxn],p; 11 int test1[maxn],test2[maxn]; 12 int c[maxn]; 13 14 void mult(int a[],int b[]){ 15 int len,i,j,tmp,k=0; 16 memset(c,0,sizeof(c)); 17 for(i=1;i<=a[0];i++){ 18 for(j=1;j<=b[0];j++) 19 { 20 tmp=a[i]*b[j]+k; 21 c[i+j-1]+=tmp%10; 22 k=tmp/10+c[i+j-1]/10; 23 c[i+j-1]%=10; 24 } 25 len=i+j-2; 26 while(k!=0) 27 { 28 c[++len]+=k%10; 29 k=k/10+c[len]/10; 30 c[len]%=10; 31 } 32 } 33 c[0]=min(len,500); 34 for(i=500;i>=0;i--) 35 a[i]=c[i]; 36 } 37 38 void qmult(){ 39 ans[ans[0]=1]=1; 40 a[a[0]=1]=2; 41 while(p){ 42 if(p&1)mult(ans,a); 43 p>>=1; 44 mult(a,a); 45 } 46 } 47 48 void dele(){ 49 int i=1; 50 while(1){ 51 if(ans[i]-1>=0) 52 { 53 ans[i]--; 54 break; 55 } 56 ans[i]=(ans[i]+9)%9; 57 i++; 58 } 59 } 60 61 void out(){ 62 int i,t=0; 63 for(i=500;i>=1;i--){ 64 cout<<ans[i]; 65 t++; 66 if(t%50==0)cout<<endl; 67 } 68 } 69 70 int main(){ 71 scanf("%d",&p); 72 cout<<(int)(log(2)/log(10)*p+1)<<endl; 73 qmult(); 74 dele(); 75 out(); 76 return 0; 77 }