快速幂
利用二进制的方式来进行实现
20=20
21=21
22=22
23=22∗2
24=24
25=24∗2
26=24∗22
27=24∗22∗2
所以我们可以看出来的是
二进制位上我们现在只有当某一位是1的时候才乘
举个例子
27=2(111)2=2(100)2∗2(10)2∗2(1)2=28∗24∗22∗21
210=2(1010)2=2(1000)2∗2(10)2=28∗22
所以原来O(b)复杂度一下降低到了O(logb)
Sample Code
1 2 3 4 5 6 7 8 9 10 11
| inline int pow(int a,int b) { int r=1,base=a; while(b) { if(b&1) r*=base; base*=base; b>>=1; } return r; }
|
矩阵乘法
定义矩阵乘法的运算方式是:
cij=k=1∑naik∗bkj
举个例子
(a1b1a2b2a3b3)⎝⎛c1c2c3⎠⎞=(a1c1+a2c2+a3c3b1c1+b2c2+b3c3)
∴(142536)⎝⎛789⎠⎞=(1∗7+2∗8+3∗94∗7+5∗8+6∗9)
∴(142536)⎝⎛789⎠⎞=(50122)
Sample Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int n;
void Up(int &x, int y) { x = (x + y) % mod; }
struct Matrix { int a[n][n]; friend Matrix operator *(const Matrix x, const Matrix y) { Matrix c; memset(c.a, 0, sizeof(c.a)); for(int i = 0; i < n;i ++) for(int j = 0; j < n;j ++) for(int k = 0; k < n;k ++) Up(c.a[i][j], x.a[i][k] * y.a[k][j] % mod); return c; } };
|
如何利用矩阵乘法计算
在计算递推式的时候,我们可以把递推式构建成矩阵乘法的样子
比如形如下列递推式的递推式:
f(n)=a∗f(n−1)+b∗f(n−2)
我们可以考虑构造成:
(a1b0)(f(n−1)f(n−2))=(f(n)f(n−1))
然后就有:
(a1b0)(f(n−1)f(n−2))=(f(n)f(n−1))
∵(a1b0)(f(n−2)f(n−3))=(f(n−1)f(n−2))
∴(a1b0)2(f(n−2)f(n−3))=(f(n)f(n−1))
(a1b0)3(f(n−3)f(n−4))=(f(n)f(n−1))
(a1b0)n−1(f(1)f(0))=(f(n)f(n−1))
然后构造起来的道理是这样,但是真正的矩阵是什么样子的还得自己知道怎么推然后再去做
假如给你一个形如f(n)=a∗f(n−1)+b∗f(n−2)+c∗f(n−3)你要是不会推还是会GG
的
然后因为有的时候dp的递推式也可以用矩阵来加速,所以用处很大
矩阵乘法快速幂
前一部分的模板
Sample Code
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
| void Up(int &x, int y) { x = (x + y) % mod; }
struct Matrix { int a[n][n]; friend Matrix operator *(const Matrix x, const Matrix y) { Matrix c; memset(c.a, 0, sizeof(c.a)); for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) for(int k = 0; k < n; k ++) Up(c.a[i][j], x.a[i][k] * y.a[k][j] % mod); return c; } };
Matrix Qpow(Matrix x, int timer) { Matrix base; for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) base.a[i][j] = 0; for(int i = 0; i < n; i ++) base.a[i][i] = 1; for(; timer; timer >>= 1, x = x * x) if(timer & 1) base = base * x; return base; }
|
PROB