如果要求 a^b %m 简单的用循环就能出来,但是复杂度 O(b)在,a,b很大的时候复杂度就很高了,在算法笔记上介绍了两种算法
1.递归思想
快速幂基于二分的思想,有时也称二分幂
(1) 如果b是奇数,那么 a^b=a * a^b-1
(2)如果b是偶数,那么a^b=a ^b/2 * a ^b/2
这样在log(b) 级别的次数转换后,就可以把 b 变成0 ,而任何正整数的0次方都是1 ,这也是递归的边界
比如x ^ 10
x ^ 5 -> x * x ^ 4 求 x ^ 4
x ^ 4 -> x ^ 2 **x ^ 2 求 x ^ 2
x ^ 2 -> x^1 * x ^ 1 求 x ^ 1
x ^ 1 -> x * x ^ 0 结束
typedef long long LL;
LL binaryPow(LL a, LL b, LL m){
if(b == 0) return 1;
if(b & 1) return a * binaryPow(a,b-1,m) % m;
else {
LL ans = binaryPow(a,b/2,m) %m;
return ans * ans %m;
}
}
& 是与运算 ,这样执行更快,也可以写成 b % 2 == 1
递归的时候不要写成 binaryPow(a,b/2,m) %m * binaryPow(a,b/2,m) %m,这样复杂度会变高
2.迭代写法
比如 2 ^ 13 可以写成 13 = 2^3 + 2^2 + 2 ^0
而13 的二级制是 1101 正好对应 幂次 ,也就是说如果当前的二进制上为1就表明22i有数,就要乘上对应的数字,其实很好理解
typedef long long LL;
LL binaryPow(LL a, LL b, LL m){
LL ans =1;
while(b > 0){
if(b & 1) ans = ans * a % m;
a * = a;
b >> 1; //将b的二进制右移1未,相当于 b/=2;
}
return ans;
}
快速幂的递归写法和迭代写法 效率都差不多 看你个人喜欢哪一种
有一道水题用递归写的,虽然很简单,但是第一次写的时候没大有思路,正好其中有一步和递归的写法相似
//水序列
//描述
//
//有个水序列如下:1 1 2 2 5 9 12 …其通项公式为f(n) = f(n-1)+f(n-2)-f(n-3) ( 4 <= n <= 30)此时,如果f(n)为奇数,还要再乘以2再减去1。给出一个整数n,请你求出该序列第n个位置上的元素。
//
//
//输入
//
//多组输入,每行一个整数n。
//
//
//输出
//
//对每组输入,单独输出一行,为第n个位置上的元素。
//
//
//输入样例 1
//
//2
//3
//4
//5
//输出样例 1
//
//1
//2
//2
//5
#include<iostream>
#include<cstdio>
using namespace std;
int f(int n){
if(n == 1 || n == 2) return 1;
if(n == 3) return 2;
if(n >= 4){
int ans = f(n-1) + f(n-2) - f(n-3);
if(ans & 1) return ans * 2 - 1;
return ans;
}
}
int main(){
int n;
while(scanf("%d",&n) != 0){
cout<<f(n)<<endl;
}
return 0;
}
递归的写法比一开始接触写的熟练多了,但是还是要勤于练习