一:矩阵快速幂算法
矩阵快速幂的思想和数的快速幂的思想是一样的,但是需要自己实现矩阵的乘法,然后套用数的快速幂模板即可。
核心: 难点在于构造矩阵,一般用于可以推出递推公式的题目,发现时间复杂度为O(n),因此可以构造一个矩阵,利用矩阵快速幂算法把时间复杂度降低到O(logn)。
矩阵的快速幂算法是用于高效的计算矩阵的高次方的。比如矩阵A*A*A*A*A*A可以变为(A*A)(A*A)(A*A),因此只需要计算一次A*A然后连乘两次就可以了,这样一共乘了三次,少于原来的五次。原理就是利用矩阵乘法的结合律来减少矩阵的重复计算的次数。
上述的例子是取一个具体的数作为一个最小单位的长度,但是也有不足之处,取一个极限的例子,当n趋于无穷大的时候,你现在取的长度与1没有什么区别的。所以应该找一个与n增长速度相适应的单位长度。
任意的一个整数都可以用一个二进制数字来进行表示,A^156 = (A^4)(A^8)(A^16)*(A^128),其中156=10011100,也就是说每一个整数的幂都可以换成二进制表示,二进制代表了这个整数可以拆分成2的位次幂之和。
(二进制采用了化连续为离散的思想,一般是为了优化一个算法才会使用它,而不是去为了解决一个问题,常见的有多重背包问题、树状数组、状态压缩DP)。
矩阵的实现通过二维数组,如果A*B=C,则c[i][j]为A的第i行与B的第j列的对应乘积的和。
const int N=100;
int C[N][N];
void multi(int A[][N] , int B[][N] ,int n)
{
memset(C,0,sizeof(C));
for(int i=0;i
{
for(int j=0;j
{
for(int k=0;k
{
C[i][j] += A[i][k] *B[k][j];
}
}
}
}
显然时间复杂度是O(n^3),至于有种更低时间复杂度的矩阵乘法方式,可以参考这个网站矩阵乘法时间复杂度分析
矩阵快速幂算法如下:
memset(res,0,sizeof(res));
for(int i=0;ii++)
{
res[i][i] = 1;
}
while(n)
{
if(n&1)
{
multi(res,a,n);
}
multi(a,a,n);
n>>=1;
}
在矩阵方面可以采用结构体进行存储,代码会相对的简洁一些,res数组的处理就是令res为单位矩阵,类似于数字快速幂算法中的ans=1,单位矩阵E的性质是E*A= A。n&1是按位与运算,同位相同为1,不同为0,这个表达式一般用于判断n的奇偶性,如果是偶数,n&1返回0;否则返回1。n>>=1是移位运算,也可以写作n=n/2。
建立矩阵递推式: 递推矩阵转移方程是T*A(n-1)=A(n)
一般来说,A(n-1)和A(n)一般都是按照原始递推式来构建的,当然可以先猜一个An,主要是利用矩阵乘法凑出矩阵T,第一行一般就是递推式,后面的行就是不需要的项就让与其的相乘系数为0。矩阵T就叫做转移矩阵(一定要是常数矩阵),它能把A(n-1)转移到A(n);然后这就是个等比数列,直接写出通项:此处A1叫初始矩阵。所以用一下矩阵快速幂然后乘上初始矩阵就能得到An。
int PowerMod(int a, int b, int c)
{
int ans =1;
a =a%c;
while(b)
{
if(b&1)
ans = (ans*a)%c;
a=(a*a)%c;
b=b/2;//或者b>>=2
}
return ans;
}
3.费马小定理
费马小定理是初等数论的四大定理之一。费马小定理(Fermat Theory)是数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
当遇到数论除法时,不应该是直接除以这个数,而是应该变成乘以它的乘法逆元。逆元的计算可以用拓展gcd,在数论取模的时候经常会遇到一个数字是1000000007。当我们除以一个数,相当于乘上1/n若x是1/n关于模N的逆元,则x=1/n (mod N),即 x*n=1(mod N)。由于我们做题时N常常为1000000007,而1000000007是个素数,所以它满足了费马小定理,而满足费马小定理说明解唯一,所以我们可以直接得出x*n=n^(N-1)。那么x=n^(N-2),即为1/n关于模N的乘法逆元。
下面给出一些习题
http://blog.csdn.net/chenguolinblog/article/details/10309423