【ACM】矩阵快速幂+快速幂+费马小定理

一:矩阵快速幂算法
矩阵快速幂的思想和数的快速幂的思想是一样的,但是需要自己实现矩阵的乘法,然后套用数的快速幂模板即可。
核心: 难点在于构造矩阵,一般用于可以推出递推公式的题目,发现时间复杂度为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<n;i++)
       {
         for(int j=0;j<n;j++)
            {
              for(int k=0;k<n;k++)
                 {
                    C[i][j] += A[i][k] *B[k][j];
                 }
            }

        }

}

显然时间复杂度是O(n^3),至于有种更低时间复杂度的矩阵乘法方式,可以参考这个网站矩阵乘法时间复杂度分析

矩阵快速幂算法如下:

memset(res,0,sizeof(res));
for(int i=0;i<n;i++)
{ 
    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。

2.快速幂取余算法
这里写图片描述

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值