麦森数(分治或快速幂)

Posted thunder-110

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了麦森数(分治或快速幂)相关的知识,希望对你有一定的参考价值。

 

 

分治: 麦森数的解题报告

题目分析:

第一问是很简单的,只需要求一个对数而已,数学原理:十进制正整数n的位数为int(log10(n))+1。所以2^P-1的位数int(log10(2)*p)+1 。

2^p = 10^(p*log10(2) )   , 所以2^p的位数是p*log10(2)。

第二问的关键是高精度乘法和指数幂的运算,而且由于题目要求最后500位数字,所以在计算乘法的时候我们只要求计算乘数的低500位就好了。

指数幂的运算不能硬乘,而要采用分治算法,否则就超时了。分治递归算法求指数幂是非常经典的,其数学原理是a^n = a^(n/2)*a^(n/2)*f(a),其中f(a) = 1(n%2==0)或f(a) = a(n%2==1)。

另外我们也可以创建一个栈,记录每次执行(n /= 2)前n的值是奇数还是偶数,然后根据上面的数学原理,模仿递归的思路,从n=1或n=0开始逆向计算a^n。

采用递归算法的时候,由于存储高精度整数数组的大小是预置MAX = 1000,所以在调用递归函数的时候要按引用传递参数,否则到了后面空间就不够分配了。

为了满足“每行输出50位”的条件,我把存储高精度整数数组的元素设置成5位数,这样输出的时候只需每行输出10个元素就行了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include <cctype>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cmath>
 7 #include<string>
 8 #include<cmath>
 9 #include<set>
10 #include<vector>
11 #include<stack>
12 #include<queue>
13 #include<map>
14 using namespace std;
15 #define ll long long
16 #define mem(a,x) memset(a,x,sizeof(a))
17 #define se second
18 #define fi first
19 const int INF= 0x3f3f3f3f;
20 const int N=1e6+5;
21 
22 int p,a[505],b[1005];
23 
24 void quick(int x)
25 {
26     if(x==0) return;
27     quick(x/2);
28     mem(b,0);    
29     for(int i=0;i<500;i++)
30     {
31         for(int j=0;j<500;j++)
32         {
33             if(x&1)     b[i+j] += a[i]*a[j]*2;
34             else   b[i+j] += a[i]*a[j];
35         }
36     }
37     for(int i=0;i<500;i++)
38     {
39         a[i] = b[i]%10;
40         b[i+1]+= b[i]/10;
41     }
42 }
43 
44 int main()
45 {
46     cin>>p;
47     a[0]=1;
48     quick(p);
49     
50     a[0]--;
51     int k=0;
52     while(a[k]<0) a[k+1]--,a[k]+=10,k++;
53     
54     cout<< floor( p*log10(2)+1 )<<endl;
55     for(int i=499;i>=0;i--)
56     {
57         cout<<a[i];
58         if((i)%50==0) cout<<endl;
59     }
60 }

 

以上是关于麦森数(分治或快速幂)的主要内容,如果未能解决你的问题,请参考以下文章

随手练——麦森数(高精度快速幂)

麦森数

2003麦森数

算法训练 麦森数

P1045 麦森数

noip2003 麦森数