zoukankan      html  css  js  c++  java
  • 算法录 之 快速幂快速乘和矩阵快速幂。

    1:

      问题如下:

      求 a^n % m 的值是多少?n是1到10^18次方的一个整数。

      求一个数的n次方,朴素的算法就是直接for循环,O(N)的复杂度。

      但是对于这个问题n实在是太大了,O(N)也会超时,那么需要更快的算法,快速幂算法。

      要求 a^n,如果知道了 a^(n/2) 次方的话,再来个平方就可以了。

      那么按照这个思路就能运用分治的思想了。

      代码如下:  

    1 int _pow(int a,long long n,int m) {
    2     if(n==0) return 1 % m;
    3 
    4     long long t=_pow(a,n/2,m);
    5 
    6     if(n%2==1) return (t*t*a) % m;
    7     else return (t*t) % m;
    8 }

      如上运用分治的思想,只需要logN的复杂度就可以得到答案。

    2:

      问题如下:

      f(1)=1, f(2)=1 , f(n)=a*f(n-1)+b*f(n-2),输出n和m,求 f(n) % m 的值。n是1到10^18次方的数。

      朴素的想法同上,直接一个for循环递推过去,这样复杂度是O(N)的,还是比较慢。

      然后想到高中的数学问题,用特征方程求这个递推式的非递推通项方程,求出是 f(n)=c1*x1^n+c2*x2^n ,这样的话应用前面的快速幂就可以求解了。

      但是x1和x2大部分情况是小数,这是求出来会有误差而且没法取模,并不能算出精确值来。

      考虑矩阵这种数学工具,构造矩阵:

      

      则求 f(n) 的话如下:

      

      那么只要用快速幂求出矩阵的n-2次方来,因为都是整数,所以不会有精度问题,也就得到了正确答案。

      也就是矩阵快速幂。

    3,快速乘:

      问题:

      求 (a*b) % m 的值,其中 a,b,m 是1到10^18。

      如果直接乘的话,因为a和b还有m都很大,那么会溢出long long,所以需要一些方法。

      朴素的想法是用数组模拟高精度,但是比较麻烦。

      还有更好的方法:

      求乘法的列竖式,

      1234*213=1234*3+1234*10*1+1234*10^2*2;

      那么如果变成二进制的话 10101 × 1011 = 10101*1+10101*2^1*1+10101*2^2*0+10101*2^3*1;

      这样代码如下:

     1 long long multi(long long a,long long b,long long m) {
     2     long long ans=0;
     3 
     4     while(b) {
     5         if(b&1) (ans+=a) %= m;
     6         (a=a*2) %= m;
     7         b/=2;
     8     }
     9 
    10     return ans;
    11 }

      就是模拟了二进制的竖式乘法,因为每次最多×2,所以不会溢出。

      这样的复杂度是 logN 的。

  • 相关阅读:
    [模板] 循环数组的最大子段和
    [最短路][几何][牛客] [国庆集训派对1]-L-New Game
    [洛谷] P1866 编号
    1115 Counting Nodes in a BST (30 分)
    1106 Lowest Price in Supply Chain (25 分)
    1094 The Largest Generation (25 分)
    1090 Highest Price in Supply Chain (25 分)
    树的遍历
    1086 Tree Traversals Again (25 分)
    1079 Total Sales of Supply Chain (25 分 树
  • 原文地址:https://www.cnblogs.com/whywhy/p/5066730.html
Copyright © 2011-2022 走看看