快速乘法&快速幂&矩阵快速幂简单讲解

快速幂算法可谓是基础但极其巧妙而优美并且非常有用的的一类算法=w=

这里介绍三种相关应用:1、快速乘法 2、快速幂 3、矩阵快速幂


一、整数运算

(a*b) mod c == ( (a mod c) * (b mod c) ) mod c

对于2进制,2^n可用1后接n0来表示、

对于8进制,可用公式 i+3*j == n (其中 0<= i <=2 ),

对于16进制,可用 i+4*j==n0 <= i <=3)来推算,

表达形式为2^i 后接 j 0


1、a*b mod p(快速乘法)


当然,一定会有吃瓜群众黑人问号脸,a*b直接算不接行了,快速乘法个鬼==

其实大部分情况下确实是没必要用快速乘法

But

乘法在计算机中的运算并没有你想象中的那么快,也要拆分成加法来做;

更常用的情况就是,在还没取模的时候,a*b已经爆了int64long long),这时则显然要用快速乘法了==,(因为在加法中不会超而且可以直接取模=w=

当然可能大家更熟悉的是快速幂,so ,这里先介绍快速乘法(就这么任性=A=

快速乘法的基本思想 ,是二进制和乘法分配律的结合,

比如说,

7=(111)2  4*7=4*1112 

用分配律展开得 4*7 == 4*100+10+12

我们不难观察出,快速幂可以通过判断当前的位(bit)是1还是0,推断出是否需要做求和操作,每次移动到下一位(bit)时,就对ans进行*2操作,等待是否求和。

(这也可以看作是二分思想的应用)

这种算法将b进行二分从而减少了不必要的运算=w=

时间复杂度是logn

=w=

function quick_power(a,b:int64):longint;//具体类型视题目而定
var
    ans:longint;
begin
   ans:=0;
   while (b<>0) do
   begin
      if (b and 1=1) then ans:=(ans+a) mod p;
      b:=b >>1;
      a:=(a+a) mod p;
   end;
   exit(ans);
end;


2、a^b mod p

快速幂其实可以看作是快速乘法的特例

在快速幂中,我们不再对ans进行*2操作,因为b已经从乘数变成了指数(人家已经升级了,而你如果还*2的话就out==),指数的相加意味着底数相乘,

But

二分的思想我们还是仍然继续可以沿用的,把b转化为2进制数

这样,我们就将原本用循环需要O(n)的算法,改进为OlogN)的算法。

=w=

var
        a,b,p,s:longint;
begin
    read(a,b,p);
    s:=1;
    while (b<>0) do
    begin
        if b mod 2=1 then s:=s*a mod p;
        b:=b >> 1;
        a:=a*a mod p;
    end;
    writeln(s);
end.


二、矩阵快速幂

由于考试中矩阵快速幂+矩阵乘法已经忘得跟不认识似的导致吃了10wa而被NM同学吐槽了一番==

矩阵的快速幂运算,其实思路和上面的整数快速幂是一样的,对指数进行二分,只不过刚才的a是整型而现在变成了矩阵而已,所以唯一的区别就是刚刚简单的 * ,如今要变成矩阵乘法的运算

矩阵快速幂的练习题可以去交一交CodevsFibonacci的一系列,用矩阵乘法+快速幂来优化Fibonacci可谓是经典中的模板题,多交几次没什么坏处(我就在今天的考试中给跪了==

=w= 

下面是Codevs 1732 AC代码

const
    mo=1000000007;
var
    n                   :int64;
    f1,f2               :array[0..2,0..2] of longint;
    a,c                 :array[0..2] of longint;
procedure mul1;
var
    j,k:longint;
begin
   fillchar(c,sizeof(c),0);
   for j:=1 to 2 do
    for k:=1 to 2 do
      c[j]:=(c[j]+(a[k] mod mo) * (f1[k,j] mod mo) mod mo) mod mo;
   a:=c;
end;

procedure mul2;  
var
    i,j,k:longint;
begin
   fillchar(f2,sizeof(f2),0);
   for i:=1 to 2 do
    for j:=1 to 2 do
     for k:=1 to 2 do
      f2[i,j]:=(f2[i,j] +(f1[i,k] mod mo)*(f1[k,j] mod mo) mod mo) mod mo;
   f1:=f2;
end;

begin
   read(n);
   while not EOF do
   begin
      f1[1,1]:=0;f1[1,2]:=1;f1[2,1]:=1;f1[2,2]:=1;
      a[1]:=1;a[2]:=1;
      dec(n);
      while (n<>0) do //矩阵快速幂
      begin
         if (n mod 2<>0) then mul1;
         n:=n div 2;
         mul2;
      end;
      writeln(a[1]);
      read(n);
   end;
end.

                                            ——by Eirlys



转载请注明出处=w=

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值