快 速 幂 {\color{Red} 快速幂} 快速幂
顾名思义:就是快速算某个数的多少次幂。
其时间复杂度为
O
(
l
g
N
)
O(lgN)
O(lgN) 比朴素的
O
(
N
)
O(N)
O(N)快了不知多少哈!
原理:
以下以求 a a a 的 b b b 次方来介绍
把 b b b 转换成二进制数。该二进制数第 i i i 位的权为 2 i − 1 2^{i-1} 2i−1;
例如:
11
11
11 的二进制是
1011
1011
1011,
11 = 2 3 ∗ 1 + 2 2 ∗ 0 + 2 1 ∗ 1 + 2 1 11=2^{3}*1+2^{2}*0+2^{1}*1+2^{1} 11=23∗1+22∗0+21∗1+21;
因此,我们将 a 11 a^{11} a11 转化为算
a 2 0 ∗ a 2 1 ∗ a 2 3 a^{2^{0}}*a^{2^{1}}*a^{2^{3}} a20∗a21∗a23;
快 速 幂 {\color{Red} 快速幂} 快速幂可以用位运算来实现
b & 1//取b二进制的最低位,判断和1是否相同,相同返回1,否则返回0,可用于判断奇偶
b>>1//把b的二进制右移一位,即去掉其二进制位的最低位
下面是两种代码:
int quickPow(int a,int b,int n)//递归形式
{
if(b==1)
return a;
if(b%2==0)//b是偶数;
{
int t=quickPow(a,b/2,n);
return t*t%n;
}
else//b是奇数;
{
int t=quickPow(a,b/2,n);
t=t*t%n;
t=t*a%n;
return t;
}
}
int quickPow(int a,int b,int n)//非递归写法;
{
int ret=1;
while(b)
{
if(b%2==1)
ret=ret*a%n;
a=a*a%n;
b=b/2;
}
return ret;
}
矩 阵 快 速 幂 {\color{Red} 矩阵快速幂} 矩阵快速幂
既然说矩阵了那么就看看矩阵长成什么样吧!
[ a b c a 1 b 1 c 1 a 2 b 2 c 2 ] \begin{bmatrix} a& b &c \\ a1 & b1 &c1\\ a2&b2&c2 \end{bmatrix} ⎣⎡aa1a2bb1b2cc1c2⎦⎤或 ( a b c a 1 b 1 c 1 a 2 b 2 c 2 ) \begin{pmatrix} a& b &c \\ a1& b1 &c1 \\ a2& b2 &c2 \end{pmatrix} ⎝⎛aa1a2bb1b2cc1c2⎠⎞
定 义 : {\color{Magenta} 定义:} 定义:
由 m × n m × n m×n 个数 a i j aij aij排成的 m m m行 n n n列的数表称为 m m m行 n n n列的矩阵,简称 m ∗ n m * n m∗n矩阵。记作:
A= [ a 11 a 12 . . . a 1 n a 21 a 22 . . . a 2 n a 31 a 32 . . . a 3 n . . . . . . . . . . . . a m 1 a m 2 . . . a m n ] \begin{bmatrix} a_{11}& a_{12} & ... & a_{1n} \\ a_{21} & a_{22} & ... & a_{2n}\\ a_{31}&a_{32}&...&a_{3n}\\ ... & ... & ... & ... \\ a_{m1} & a_{m2} & ... & a_{mn} \end{bmatrix} ⎣⎢⎢⎢⎢⎡a11a21a31...am1a12a22a32...am2...............a1na2na3n...amn⎦⎥⎥⎥⎥⎤
这 m × n m×n m×n 个数称为矩阵 A A A的元素,简称为元,数 a i j a_{ij} aij位于矩阵 A A A的第 i i i行第 j j j列,称为矩阵 A A A的 ( i , j ) (i,j) (i,j)元,以数 a i j a_{ij} aij为 ( i , j ) (i,j) (i,j)元的矩阵可记为 ( a i j ) (a_{ij}) (aij)或 ( a i j ) (a_{ij}) (aij) m ∗ n m * n m∗n, m ∗ n m*n m∗n矩阵 A A A也记作 A m n A_{mn} Amn。
矩 阵 乘 法 {\color{Magenta}矩阵乘法} 矩阵乘法:
两个矩阵的乘法仅当第一个矩阵A的列数和另一个矩阵B的行数相等时才能定义。如A是m×n矩阵和B是n×p矩阵,它们的乘积C是一个m×p矩阵 ,它的一个元素:
c i , j = a i , 1 b 1 , j + a i , 2 b 2 , j + ⋅ ⋅ ⋅ + a i , n b n , j = ∑ r = 1 n a i , r b r , j c_{i,j}=a_{i,1}b_{1,j}+a_{i,2}b_{2,j}+\cdot \cdot \cdot +a_{i,n}b_{n,j}=\sum_{r=1}^{n}a_{i,r}b_{r,j} ci,j=ai,1b1,j+ai,2b2,j+⋅⋅⋅+ai,nbn,j=∑r=1nai,rbr,j;
并将此乘积记为: C = A B C=AB C=AB;
例如:
[ 1 0 2 − 1 3 1 ] ∗ [ 3 1 2 1 1 0 ] = [ ( 1 ∗ 3 + 0 ∗ 2 + 2 ∗ 1 ) ( 1 ∗ 1 + 0 ∗ 1 + 2 ∗ 0 ) ( − 1 ∗ 3 + 3 ∗ 2 + 1 ∗ 1 ) ( − 1 ∗ 1 + 3 ∗ 1 + 1 ∗ 0 ) ] = [ 5 1 4 2 ] \begin{bmatrix} 1 & 0 &2 \\ -1& 3 & 1 \end{bmatrix}*\begin{bmatrix} 3&1 \\ 2 & 1\\ 1 & 0 \end{bmatrix}=\begin{bmatrix} (1*3+0*2+2*1)&(1*1+0*1+2*0) \\ (-1*3+3*2+1*1)&(-1*1+3*1+1*0) \end{bmatrix}=\begin{bmatrix} 5 & 1 \\ 4 &2 \end{bmatrix} [1−10321]∗⎣⎡321110⎦⎤=[(1∗3+0∗2+2∗1)(−1∗3+3∗2+1∗1)(1∗1+0∗1+2∗0)(−1∗1+3∗1+1∗0)]=[5412];
矩阵的乘法满足以下运算律:
结合律:
(
A
B
)
C
=
A
(
B
C
)
(AB)C=A(BC)
(AB)C=A(BC)
左分配律:
(
A
+
B
)
C
=
A
C
+
B
C
(A+B)C=AC+BC
(A+B)C=AC+BC
右分配律:
C
(
A
+
B
)
=
C
A
+
C
B
C(A+B)=CA+CB
C(A+B)=CA+CB
矩阵乘法一般不满足交换律。
代码如下:
const int N=100;
int c[N][N];
void multi(int a[][N],int b[][N],int n)//n是矩阵大小,n<N
{
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c[i][j]+=a[i][k]*b[k][j];
}
另一种写法:
int c[N][N];
void multi(int a[][N],int b[][N],int n)
{
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
c[i][j]+=a[i][k]*b[k][j];
}
这种可以在第二重 f o r for for判断 i f ( a [ i ] [ k ] = = 0 ) c o n t i n u e ; if(a[i][k]==0)continue; if(a[i][k]==0)continue;对于矩阵有较多0的有一定效果。不过一般第一种写法就够了,这种知道就行。
显然矩阵乘法的复杂度是 O ( n 3 ) O(n^{3}) O(n3);( O ( n 2.7 ) O(n^{2.7}) O(n2.7)的方法不会写,无视这里)。
这里我直接写的是 n ∗ n n*n n∗n的矩阵(即方阵),显然两个相乘是要一行和一列对应乘,那么矩阵乘法是需要 A A A的行数与 B B B的列数相等的(这是 A ∗ B A*B A∗B的前提条件,可见矩阵的乘法是不满足交换律的)。然而这些一般都是没什么用的,矩阵快速幂只会用到方阵(除非题目是裸的矩阵乘法)。矩阵快速幂都是方阵也就避免的相乘的前提条件,可以放心用。
矩 阵 快 速 幂 {\color{Magenta} 矩阵快速幂} 矩阵快速幂:
就是算 A n A^n An;方法很简单,把快速幂算法中的乘法改成矩阵的乘法就可以了(网上搜的代码,????)
代码如下:
const int N=10;
int tmp[N][N];
void multi(int a[][N],int b[][N],int n)
{
memset(tmp,0,sizeof tmp);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
tmp[i][j]+=a[i][k]*b[k][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=tmp[i][j];
}
int res[N][N];
void Pow(int a[][N],int n)
{
memset(res,0,sizeof res);//n是幂,N是矩阵大小
for(int i=0;i<N;i++) res[i][i]=1;
while(n)
{
if(n&1)
multi(res,a,N);//res=res*a;复制直接在multi里面实现了;
multi(a,a,N);//a=a*a
n>>=1;
}
}
不过上诉 r e s res res数组就等同于普通快速幂初始化的 1 1 1,原理想通的,这个矩阵叫单位矩阵E,性质就是 E ∗ A = A E*A=A E∗A=A,就是 1 ∗ a = a 1*a=a 1∗a=a,一样,单位矩阵就是对角线全是1其他全是 0 0 0,最终算出的结果是一个 r e s res res矩阵;
未 完 待 续 ⋅ ⋅ ⋅ ⋅ {\color{Red} 未完待续\cdot\cdot\cdot \cdot} 未完待续⋅⋅⋅⋅