快速幂的那些小事儿

快速幂的那些小事儿

快速幂

众所周知,C++中提供了pow函数方便计算一个数的幂次方,那此时,就需要一个一个底数往上乘

此时时间复杂度为$O(n)$的时间复杂度,那么有没有更快的的办法呢?快速幂可以压缩到$O(logn)$

快速幂是根据其二进制完成时间复杂度的压缩

对于任意一个数,可以将他化为二进制,那么此时他的每一位就变成了0或者1

 n = 10010101
1 0 0 1 0 1 0 1
128 64 32 16 8 4 2 1

即n等于每一位的2的幂次然后如果为1那就加上,如果为零,那就不加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>

using namespace std;

#define ll long long

const int N = 2e5 + 10, M = 200010;

int qpow(int a,int b)
{
int r = 1;
while(b)
{
if(b&1) r *= a;
a *= a;
b >>= 1;
}
return r;
}

void solve()
{
int n, k;
cin >> n >> k;
cout << qpow(n, k) << '\n';
}
int main()
{
int t = 1; // cin >> t;
while(t --)
{
solve();
}
return 0;
}

矩阵快速幂

斐波那契数列

$f(n)=f(n - 1) + f(n - 2)$

可得出 0 1 1 2 3 5 8 13 ….. ,如果将其两两配对变成<0,1>,<1,1>,<1,2>,<2,3> ….

过程

且通过可以通过快速幂对这个过程进行优化

代码如下:

其中需要一个单位矩阵,作为快速幂运算中的1的替代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<iostream>
#include<vector>
#include<cstring>

using namespace std;

#define ll long long
#define th this

const int N = 1e5 + 10;
const int rc = 2;
const int MOD = 1e9 + 7;

struct matrix{
int matr[2][2];
matrix(){memset(matr,0,sizeof matr);};
// operator
matrix operator*(matrix b)
{
matrix a;
for(int i = 0;i < rc;i ++)
for(int j = 0;j < rc;j ++)
for(int k = 0;k < rc;k ++)
a.matr[i][j] += 1ll * th->matr[i][k] * b.matr[k][j];
return a;
}
};

matrix qpow(matrix a,int b)
{
matrix r;

r.matr[0][0] = r.matr[1][1] = 1;

while(b)
{
if(b&1) r = r * a;
a = a * a;
b >>= 1;
}
return r;
}

void solve()
{
int n;
matrix a;
a.matr[0][1] = a.matr[1][0] = a.matr[1][1] = 1;

cin >> n;

matrix tt = qpow(a, n);

cout << tt.matr[0][0] << '\n';
}

int main()
{
int t = 1; //cin >> t;
while(t --)
{
solve();
}
return 0;
}

快速幂的那些小事儿
http://example.com/2024/04/09/快速幂的小芝士/
作者
smg
发布于
2024年4月9日
许可协议