输入数据包含多个测试实例,  1.1.已知的方法

作者:澳门娱乐

O(logn)的急迅幂,logn

高效幂原理分析与任何情势回想

 

目录:
大器晚成.纪念朴素法与行使库函数,解析利弊。

二.引例:指数的疏解,即高速幂的法规。

三.源代码。

 

正文:

 一.回顾

  1.1.已知的主意

  关于求a的n次方,有二种做法呐?对于初读书人的话有三种。如下所示

1 void poww1(int a, int b){
2     long long ans = 1;
3     for(register int i = 0; i < b; i++)
4         ans *= a;
5     return ans;
6 }

1  #include <cmath>//poww2
2     ans = (long long) pow(a, b);//调用cmath库的pow函数,但是注意返回值不是longlong/int型,是double型

  观望poww1,八个明明的标题就是它的时光复杂度相比高,是O(n)的复杂度,即n次方必要乘n次才可获取结果,超慢。

  观看poww2,特别简明的标题在于其函数的再次来到值是个浮点数,那是三个准时炸弹,有异常的大希望采用pow(10, 4)时获得9999的答案,让您调节和测验后欲哭无泪。

 

  1.2. 测量检验对照

  测量试验程序如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 using namespace std;
 5 int main(){   
 6      int n = 0;  
 7      for(int i = 0; i <= 4; i++)  
 8          n += (i+1)*(int)pow(10, 5-i);  
 9      cout << n << endl;  
10      return 0;  
11 }

 

  使用Dev-C++ 5.4.0Smart c++ 2013分级运行,得到测验数据:

澳门娱乐6165 1

  由于精度难题,结果分裂。

  有人会说:"不要强转成int啊,用long long 就不会遗弃精度啦。"

  那么将循环改成——

1 for(int i = 0; i <= 4; i++)  
2     n += kong[i]*(long long)pow(10, 5-i); 

  测验结果如下:

澳门娱乐6165 2

  根本就一向不改变哎!

 

  1.3.对照二种艺术运转的时辰与准确性

  利用循环次数越来越大的测量试验程序如下:

1     int i;  
2     long long n = 0;  
3     for(i = 0; i <= 10; i++){
4         n += (i+3)*(long long)pow(5, 11-i);  
5     }
6     cout << n << endl;  

 1 long long poww(int a, int b){
 2     long long ans = 1;
 3     for(int i = 0; i < b; i++)
 4         ans *= a;
 5     return ans;
 6 }
 7 int main(){  
 8     int i;  
 9     long long n = 0;  
10     for(i = 0; i <= 10; i++){
11         n += (i+3)*(long long)pow(5, 11-i);  
12     }
13     cout << n << endl;  
14     return 0;  
15 }

  运维结果如下:

澳门娱乐6165 3  (上下分别是办法二与措施意气风发卡塔尔

 

  **1.4. 结论**

  两个优劣不言而喻:方法一相对一点也不慢且保证在不超过限度量内必定将不利,可是要多打几行代码;方法二短,但是坑。

  若接纳上述两种艺术,自个儿选呢。。。

  那么大家的指标正是三回九转方法少年老成的长处,修改其症结:即维持正确性的情事下减弱时间复杂度。

 

 二.飞速幂引理

  2.1.先看功效:

澳门娱乐6165 4

  答案黄金时代致,时间不到方法生龙活虎的59%,并且在当次方数不小的时候,时间会远低于方法朝气蓬勃,原因便是因为其时间复杂度为O(logn)(logn通常指log2n)

 

  2.2引理的数学情势

  引理:∀ 取X∈N*皆可被解释为形如X = 2^a+2^b+...+2^k(a != b!= …… != k);

  设2^0+2^1+2^2+…+2^n = m;……(1)式

  2^1+2^2+2^3+…+2^(n+1) = 2*m;……(2)式

  (2)式-(1) 式= (1)式 = 2^(n+1)-2^0 = 2^(n+1)-1……(*)

  当X != 2^m时

  ∵int X > 0;

  ∴ X = 2^m - 1 - k(int k >= 0);

  if(x%2 == 1)  k %2 == 0;

  else k%2 == 1;

  ∵2^m - 1 = 2^0 + 2^1 + … +2^(m-1);

  ∴若原式创建,则k可分解为2或多或少次方的和。

  当k%2 == 1时,必有2^0,减掉,k为偶数;

  那么现在X 就裁减为了正偶数。

  观看2 4 8 16 ……我们会开掘有个别,即第i个数前边的数都2^i有作为因数,而它眼下的数因数中则从未2^i,通过这些便得以鲜明k的表达。

  利用递归的思想……X缩小为4的倍数,8的倍数……

 

  **2.3例子:**

  举个例证 : k = 17的分解,遵照以下步骤。

  int cnt = 1;

  while (k){

   if(k%(2^cnt) != 0) {

    k获得新的演讲 : 2^(cnt-1);

    k -= 2^(cnt-1);

    //此时k%2(cnt) == 0

    cnt ++;

  }

 }

  17%2 == 1; => 17 = 2^0 + m; 17-1 = 16;

  16%2 == 0; => 16/2 = 8 

  ……

  1%2 == 1; =>17 = 2^0 +2^4;

   三分之一 == 0 终止循环; 

澳门娱乐6165,  那么这种东东对做幂运算有哪些用呢?

  答案正是 —— 将幂遵照此办法分解

  例如:求6^11

  大家已知 6^0 = 1 ,a =  6^1 = 6;

  11 = 2^0 + 2^1 + 2^3;

  所以 6^11 == 6^1 * 6^2 * 6^8;

  大家还驾驭 a^2 == 36;

  那么大家将上述解释指数的手续参与乘法以拿到最终解:

  curr = 6;ans = 1;

  11 % 2 == 1 => ans *= 6^0;curr = 6^2

  5 %2 == 1 => ans *= 6^2;curr = 6^4;

  2%2 == 0 =>curr = 6^8;

  1%2 == 0 ans *=curr; ans = 6^11;

  大器晚成共用了ceil(log(2)11) = 4 步

  每便curr自己平方三回,以备选下二次的接纳。而当k%2 == 1 时,就表示必要利用curr将指数进行分解。

 

  2.4.源代码 

  那么给出源代码:

 1 void poww(int a, int b){
 2     int cnt = 0;
 3     long long curr = a,ans = 1, last;
 4     while (b){
 5         if(b%2)    ans *= curr;
 6         curr *= curr;
 7         b /= 2;
 8         cnt ++;
 9     }
10     return ;
11 }

  步骤与地点大同小异。

  由此,快捷幂便成功了。 

  箜瑟_qi 2016.02.08

快捷幂原理深入分析与任何模式回看 目录: 后生可畏.想起朴素法与使用库函数,深入分析利弊。 二.引例:指数的解说,即神速幂的...

Problem Description

求A^B的终极几个人数表示的卡尺头。
表明:A^B的意义是“A的B次方”

 Input

输入数据蕴含八个测量试验实例,每一种实例占生龙活虎行,由四个正整数A和B组成(1<=A,B<=10000卡塔尔,假设A=0, B=0,则意味输入数据的扫尾,不做拍卖。

 Output

对此各样测量试验实例,请输出A^B的终极肆个人表示的卡尺头,每一种输出占大器晚成行。

  简单的讲那题就是要求高次幂,有二种格局能够兑现。

  第风姿洒脱总相比土鳖,每一次乘完对1000取余也得以过。

  我要讲的是第两种听上去很宏大上的方式——飞速幂。为啥叫快快幂呢?因为用它求幂相当慢,对于x^n,复杂度为O(logn卡塔尔,是还是不是很吊!快速幂的原理是把幂分解,把三个不小的幂分解成非常的小的几部分。举例:

11的二进制是1011

11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1

因此,我们将a¹¹转化为 澳门娱乐6165 5

即把n化为2进制数,各种为1的位都是超小的一片段。那样能够用叁个循环来消除。上面是快速幂的非递归代码,一时忽视max

int cal(int x, int n, int max){

  int sum = 1;    //最终输出的结果
  while (n > 0){   //当幂降为0是终结
  if (n & 1)      //位运算,&是按位与,当两侧都为1,表明式为1,那个是用来判定二进制数最终壹位是或不是为1,这里n是以二进制的样式比较的

    sum = sum*x%max;//要是为1,sum就要乘x^i,i为该位在二进制数中之处
  n >>= 1;      //>>为位运算符,右移一个人,即去掉已经计算过的黄金时代部分
  x = x*x%max;    //用来标识记录x^2^i,循环i次即去掉了i位,当第i+1位为1时,sum将在乘x^2^i;
  }
  return sum;//循环停止再次来到结果。
}

  今后来说max的效果与利益,用来把数变小的,大家得以想象假设是相当大的数的超高次方,乘三遍后数据相当的大不能用任何叁个主干数据类型表示,并且那也是不供给的,常常大家只需求掌握最终若干位的值,这就足以用到取余了,余数的幂和原数的幂在余数的位数上是相同的,所以每一回举行乘法运算后都要取余,当然假诺数额十分小也足以不用取余。

  好了,感到小编已经讲的很详细了!!真的是努力了。。。

上边贴上地方那题的代码

 1 #include<iostream>
 2 using namespace std;
 3 
 4 int cal(int x, int n, int max){
 5     int sum = 1;
 6     while (n > 0){
 7         if (n & 1)
 8             sum = sum*x%max;
 9         n >>= 1;
10         x = x*x%max;
11     }
12     return sum;
13 }
14 int main(){
15     int x, n;
16     while ((cin >> x >> n) && (x || n)){
17         cout << cal(x, n, 1000) << endl;
18     }
19     return 0;
20 }

 

本文由澳门娱乐6165发布,转载请注明来源

关键词: