麦森数(分治或快速幂)

 

 

分治: 麦森数的解题报告

题目分析:

第一问是很简单的,只需要求一个对数而已,数学原理:十进制正整数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 }

 

接下来 套一套快速幂的模板。。

 

 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[1005],b[1005],c[1005],f[1005],d[1005];
23 
24 void work1()
25 {
26     mem(c,0);
27     for(int i=0;i<500;i++)
28     {
29         for(int j=0;j<500;j++)
30         {
31             c[i+j] += a[i]*b[j];  //数组a就是原来快速幂模板中的ans, 数组b就是a 
32         }
33     }
34     for(int i=0;i<500;i++)
35     {
36         f[i]=c[i]%10;
37         c[i+1]+=c[i]/10;
38         a[i]=f[i]; //更新a数组,即实现ans*=a的步骤 得到ans*=a后的ans 
39     }
40 }
41 void work2()
42 {
43     mem(d,0);
44     for(int i=0;i<500;i++)
45     {
46         for(int j=0;j<500;j++)
47         {
48             d[i+j] += b[i]*b[j];
49         }
50     }
51     for(int i=0;i<500;i++)
52     {
53         b[i]=d[i]%10;  //更新b数组,即实现 a*=a的步骤 
54         d[i+1]+=d[i]/10;
55     }
56 }
57 
58 void quick(int x,int y)
59 {
60     a[0]=1;  //ans  相当于给ans赋初值1 
61     b[0]=x; // a  给a赋初值 2
62     while(y)
63     {
64         if(y&1) work1();
65         y>>=1;
66         work2();
67     }
68 }
69 
70 int main()
71 {
72     cin>>p;
73     quick(2,p);
74     
75     f[0]--; int k=0;
76     while(f[k]<0) f[k]+=10,f[k+1]--,k++;
77     
78     cout<<floor(p*log10(2)+1) <<endl;
79     for(int i=499;i>=0;i--)
80     {
81         cout<<f[i];
82         if(i%50==0) cout<<endl;
83     }
84     
85 }

 

posted @ 2018-07-30 12:10  木流牛马  阅读(220)  评论(0编辑  收藏  举报