快速求幂(Quick Exponentiation)
接触ACM没几天,向各路大神求教,听说ACM主要是研究算法,所以便开始了苦逼的算法学习之路。话不多说,RT所示,学习快速求幂。
在头文件<math.h>或是<cmath>中,double pow( double x, double y );函数是用来快速求x^y,于是便从pow函数来说起,以下大体上是pow的函数代码:
- int pow(int x, int n)
- {
- int num = 1;
- while (n != 0){
- num = num *x;
- n = n -1;
- }
- return num;
- }
通过以上程序,2^5 = 2*2*2*2*2的流程中一共进行了4次乘法。试想若是大数2^99999999.......,这样循环的算下来肯定要计算到猴年马月。那么我们有什么办法可以简化我们的幂指运算呢?
分析数据
2^4=2^2 * 2^2;
2^5=2^2 * 2^2 * 2
2^6=2^3 * 2^3
2^7=2^3 * 2^3 * 2
……
x^n = x^(n/2) * x^(n/2) (n为偶数)
x^n = x^(n/2) * x^(n/2) * n (n为奇数)
显然这种算法分析利用分治思想(divide and conquer)。通过这种方式,我们可以根据通项公式写出递归函数求分制幂指运算的函数代码:
- int DC_pow(int x, int n)
- {
- if (n==1) return x;
- if (n==0) return 1;
- else if (n & 1) return DC_pow(x,n/2)*DC_pow(x, n/2)*x; // 对应公式x^(n/2) * x^(n/2) * n
- else return DC_pow(x,n/2)*DC_pow(x, n/2); // 对应公式x^(n/2) * x^(n/2)
- }
由此我们以分治思想,减少了运算量。接下来,我们研究此递归代码的一些细节。对于n/2,我们在二进制位运算中还有其他的处理方式,倘若一个数是二进制数,只要我们将该数右移一位(x>>1),即可对其真值除以2。也许你又会想,DG想表述的是什么意思,即使我把代码中的n/2换成n>>1运算量有没有改变,到底意义何在呢?我们从一个例子引出:
♢问题:请求出3^999=?(问题目的在于感受不同求解方法的复杂程度)
分析:我们先调用最最基本的方式进行求解,即为求:3 * 3 * …… * 3(999个3),这样一共要进行998次乘法运算。这种方法显然是太麻烦,反复的递归,计算机心里定会默念“我靠,坑爹啊!”
接下来,我们使用简单分制思想来做此题,这样就可以大大简少运算次数,使得计算次数仅为9次。但是,如果你也在学习ACM的话,你会懂得递归做法运行速度之慢。即使递归函数通俗易懂,即使写法简单,但是并不推荐。你若不信,我给大家举一个简单的例子:
利用欧几里德算法(辗转相除法)计算两数的gcd(最大公约数)
递归形式:
- int gcd(int a,int b)
- {
- if(a == 0) return b;
- else return b == 0?a:gcd(b,a%b);
- }
非递归形式:
- int gcd(int a,int b)
- {
- int c;
- if(a == 0) return b;
- while(b!=0) c = b,b = a % b,a = c;
- return a;
- }
以上利用相同的思想进行求解a,b的gcd,但是效率有很大偏差,大家可以尝试。
那么,还有什么方法来求解这个问题呢,接下来便是经典的快速求幂法。我们将3^999进行分解,即为: (3 ^ 512) * (3 ^ 256) * (3 ^ 128) * (3 ^ 64) * (3 ^ 32) * (3 ^ 4) * (3 ^ 2) * 3。这时候,我们可以整理出3的指数部分形式:2^9+2^8+2^7+2^6+2^2+2^1+2^0。然后,我们再把999转换成2进制为1111100111,2进制的转换作为指数位置的数。由此,我们同样的利用了分治思想,将指数分成了2的n次方和的形式。配合上右移运算,我们只要将其二进制数与1做与运算,为真则将此位上的2^n次方加入,为假则不加入。下面放出代码:
- int spow(int x, int n)
- {
- int result = 1;
- while (n > 0)
- {
- if (n & 1) result *= x;
- x *= x;
- n >>= 1; //n=n/2
- }
- return result;
- }
以上便是全部内容,第一次发文,多有错误。多多包含。
学习本块知识参考过的博文:
http://blog.csdn.net/zhizichina/article/details/7573342
http://blog.csdn.net/hkdgjqr/article/details/5381028
关于快速求幂的ACM题集:
HDU1575、HDU1852、HDU2817、HDU2035.
快速求幂(Quick Exponentiation)的更多相关文章
- NYOJ--102--次方求模(快速求幂取模)
次方求模 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 求a的b次方对c取余的值 输入 第一行输入一个整数n表示测试数据的组数(n<100)每组测试只有一 ...
- HDU 2035 人见人爱A^B(二分求幂,快速求幂)
题意:求A的B次方的后三位数字 思路1:常规求幂,直接取余求解 代码: #include<iostream> #include<cstdio> using namespace ...
- Quick Pow: 如何快速求幂
今天讲个有趣的算法:如何快速求 \(n^m\),其中 n 和 m 都是整数. 为方便起见,此处假设 m >= 0,对于 m < 0 的情况,求出 \(n^{|m|}\) 后再取倒数即可. ...
- ahjesus js 快速求幂
/* 快速幂计算,传统计算方式如果幂次是100就要循环100遍求值 快速幂计算只需要循环7次即可 求x的y次方 x^y可以做如下分解 把y转换为2进制,设第n位的值为i,计算第n位的权为x^(2^(n ...
- NYOJ-127 快速求幂,最小生成树
#include"iostream" using namespace std; int kuaisuqiumo(int a,int b,int c){ ; a = a % c; ) ...
- hdu 1005 Number Sequence(矩阵连乘+二分快速求幂)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1005 代码: #include<iostream> #include<stdio.h&g ...
- 【板子】gcd、exgcd、乘法逆元、快速幂、快速乘、筛素数、快速求逆元、组合数
1.gcd int gcd(int a,int b){ return b?gcd(b,a%b):a; } 2.扩展gcd )extend great common divisor ll exgcd(l ...
- 九度OJ 1085 求root(N, k) -- 二分求幂及快速幂取模
题目地址:http://ac.jobdu.com/problem.php?pid=1085 题目描述: N<k时,root(N,k) = N,否则,root(N,k) = root(N',k). ...
- 二分求幂/快速幂取模运算——root(N,k)
二分求幂 int getMi(int a,int b) { ; ) { //当二进制位k位为1时,需要累乘a的2^k次方,然后用ans保存 == ) { ans *= a; } a *= a; b / ...
随机推荐
- 《Android开发艺术探索》读书笔记 (9) 第9章 四大组件的工作过程
第9章 四大组件的工作过程 9.1 四大组件的运行状态 (1)四大组件中只有BroadcastReceiver既可以在AndroidManifest文件中注册,也可以在代码中注册,其他三个组件都必须在 ...
- codevs2622数字序列( 连续子序列最大和O(n)算法)
/* 算法描述:维护一个s[p]表示累加和 并且更新最大值ans 如果s[p]<0 则从p+1重新累加 证明:设某个区间的起点和终点分别为s t 分两种情况 1.t<p:设s2表示1到s的 ...
- css.day.05.eg
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- ViewPager循环广告位的实现
1.如何实现循环播放 2.如何实现自动循环 如何实现循环播放 现在网上实现循环播放都是在adapter的getCount()方法返回一个较大的值并且instantiateItem(ViewGroup ...
- 安卓开发入门之activity
安卓开发主要用到的是java语言,对于一个activity,自己写的程序可以继承至Activity,该Activity先会运行一个叫 onCreat()的类,可以在其中申明一些初始化的函数等,这个函数 ...
- [LeetCode OJ] Reorder List—Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
For example,Given {1,2,3,4}, reorder it to {1,4,2,3}. /** * Definition for singly-linked list. * str ...
- 【USACO 1.2.5】双重回文数
[题目描述] 如果一个数从左往右读和从右往左读都是一样,那么这个数就叫做“回文数”.例如,12321就是一个回文数,而77778就不是.当然,回文数的首和尾都应是非零的,因此0220就不是回文数. 事 ...
- Oracle高级查询,事物,过程及函数
一 数值函数 数值 abs,ceil,floor,round,trunc字符串 instr,substr SQL>SELECT 'ABS':'|| ABS(-12.3) FROM DUAL; 运 ...
- 如何让IIS 8.0支持无后缀图片的访问
进入“MIME类型”模块后,我们点击右侧的“添加”,然后填好文件扩展名和类型值.对于无后缀的图片文件,扩展名只需填写“点”符号即可,类型值根据图片文件实际的扩展名填写.如果是jpeg格式的,那么就填写 ...
- LIKE匹配关键字
1.% 匹配任意数目字符(包括零个字符) SELECT * FROM edo_user WHERE true_name LIKE '王%' 应用:关键字查询 WHERE u.true_name lik ...