高精快速幂——洛谷P1045麦森数~2020.7.14学习笔记

高精快速幂——洛谷P1045麦森数~2020.7.14学习笔记_第1张图片
输入输出样例
输入:

1279

输出:

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

很明显,拿到这道题,要结局的由两部分。第一部分是求2的n次幂-1位数。易得,2的n次幂-1的位数与2的n次幂的位数相同(因为2的n次结尾一定不会带0),因此,计算位数只需计算2的n次所得的数字的位数即可。
计算方法如下
易知,10的n次幂的数字的位数为n,只需做一些小小的改动,将2的n次幂放在10的指数位置上即可,2 ^ n 也作 10 ^ log 10 ( 2 ^ n ) ,可化简为:10 ^ (log 10 ( 2 ) * n),因此,所求位数即为 :log 10 ( 2 ) * n(c++的cmath头文件自带计算log10()的函数)。

解决了位数问题,下面来解决高精度计算的问题。
在这里插入图片描述
显而易见,本题想要不爆TLE,需要使用快速幂(2的n次幂,显而易见)。
快速幂的原理又是什么呢?您可以自行前往CSDN搜索,CSDN中不乏优秀的博主,比以下笔者的见解强上千倍万倍,笔者的思路,亦是从其他博文学习而来的。
举个例子,计算 3^10 ,可以拆分为:3333333333,简单地使用循环,需要计算10次,看似很快,但当n的值无穷大时,循环的暴力做法便失效了。因此,我们另辟蹊径,拿出一个33,结果为9,那么这个计算便简化为 3 ^ 8 * 9 ,然而,指数只是减小了2,仍不能避免多次的计算,因此,换个思路,我们应想法设法地减小指数,而不是将多次操作不断分割。若换成(3*3)^ 5,即9 ^ 5,这样计算的时间直接减半,而此时,由于指数变为奇数,不能再进行 /2 的指数分割,便提出一个9,使指数变为4次,再进行分割运算。因此,到最后,仅需计算9×6561(9 ^ 4的结果),即可得到最终答案。下面是快速幂的代码实现:

typedef int ElemType;
ElemType fastPower(ElemType base,ElemType power){
     
 //base代表底数,power代表指数
 ElemType result = 1;
 while( power > 0 ){
     
  if( power & 1 ) /*power按位与1,若结果为奇数,返回1(true),为偶数,
  返回0(false)根本目的是判断此时指数的奇偶性*/ 
  {
     
   result = result * base; /*所求目标过大时,题目中可能会让答题人
   对结果求余,求余操作应该加在每一步 */ 
   } 
  power>>=1;/*power右移一位,即除二操作,此时不奇偶,都应该执行除二
  操作,因不论是否为偶数,C/C++的除二都会保留除二后的整数部分,即:
  等价于先化为不大于该数的偶数,再除二。而“奇数提出”的操作再上一
  步if条件句已经执行了。 */ 
  base*=base;//指数截半,底数加倍 
 } 
 return result;
}

高精度自然不在话下了,观看并仔细模拟下方完整代码自然能懂。但今日使用高精乘法时,有一个很大的收获,在此分享给大家,那就是:使用int数组进行高精计算强于使用字符串进行高精计算。(大大降低了算法难度,但代价提高了程序占用空间
下面放出完整代码:

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const ll maxn = 10010;
const int Lim = 500;
ll len;
int result[maxn]={
     1,1},base[maxn]={
     1,2};
void cal(int a[],int b[]){
     
 int tmp[maxn] = {
     0};
 tmp[0] = a[0]+b[0];
 if(tmp[0]>500) tmp[0] = 500;
 for(int i=0;i<a[0];i++){
     
  for(int j=0;j<b[0];j++){
     
   tmp[i+j+1] = a[i+1]*b[j+1] + tmp[i+j+1];
   if(tmp[i+j+1]>=10){
     
    tmp[i+j+2] += tmp[i+j+1]/10;
    tmp[i+j+1] %= 10;
   }
  }
 }
 for(int i=0;i<=tmp[0];i++) a[i]=tmp[i];
}
void Print(){
     
 for(int i=1,j=500;i<=500;i++){
     
  cout<<result[j--];
  if(i%50 == 0) cout<<endl;
 }
}
int main()
{
     
 ll p;
 cin>>p;
 len = log10(2)*p+1;
 cout<<len<<endl;
 
 while(p>0){
     
  if(p&1){
     
   cal(result,base);
  }
  p>>=1;
  cal(base,base);
 }
 result[1]-=1;
 Print();
 cout<<endl;
 return 0;
}

高精快速幂——洛谷P1045麦森数~2020.7.14学习笔记_第2张图片愉快的AC(学习题解+查找资料刚看到题目时我是完全不会做的,AC后便学会了快速幂并优化了使用高精的思路)。(注:输出有坑,请仔细看题,笔者在输出倒了两次。)

你可能感兴趣的:(基础算法代码共享,算法,洛谷)