算法录 之 快速幂快速乘和矩阵快速幂。

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 的。

时间: 2024-10-25 20:09:03

算法录 之 快速幂快速乘和矩阵快速幂。的相关文章

hdu 3221 Brute-force Algorithm(快速幂取模,矩阵快速幂求fib)

http://acm.hdu.edu.cn/showproblem.php?pid=3221 一晚上搞出来这么一道题..Mark. 给出这么一个程序,问funny函数调用了多少次. 我们定义数组为所求:f[1] = a,f[2] = b, f[3] = f[2]*f[3]......f[n] = f[n-1]*f[n-2].对应的值表示也可为a^1*b^0%p,a^0*b^1%p,a^1*b^1%p,.....a^fib[n-3]*b^fib[n-2]%p.即a,b的指数从n=3以后与fib数列

2017省夏令营Day7 【快速幂,筛法,矩阵快速幂,线段树】

题解:首先,我们可以得到一个规律:经过2次变换后,a和b的值都分别乘2了,所以只要用快速幂就能过啦,但是,要特判n为0的情况. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define Mod 1000000007 5 using namespace std; 6 long long a,b,n,ans1,ans2; 7 long long power(long long x)

P3390 【模板】矩阵快速幂

题目背景 矩阵快速幂 题目描述 给定n*n的矩阵A,求A^k 输入输出格式 输入格式: 第一行,n,k 第2至n+1行,每行n个数,第i+1行第j个数表示矩阵第i行第j列的元素 输出格式: 输出A^k 共n行,每行n个数,第i行第j个数表示矩阵第i行第j列的元素,每个元素模10^9+7 输入输出样例 输入样例#1: 2 1 1 1 1 1 输出样例#1: 1 1 1 1 说明 n<=100, k<=10^12, |矩阵元素|<=1000 算法:矩阵快速幂 如题,矩阵快速幂. 已知,矩阵乘

poj 3070 Fibonacci 矩阵快速幂

题目链接:http://poj.org/problem?id=3070 In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, … An alternative formula for t

Fibonacci----poj3070(矩阵快速幂, 模板)

题目链接:http://poj.org/problem?id=3070 . 就是斐波那契的另一种表示方法是矩阵的幂: 所以是矩阵快速幂:矩阵快速幂学习 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include<math.h> using namespace std; #define N 10 struct node { int a[

Uva10689 Yet another Number Sequence ( 矩阵快速幂 )

Uva 10689Yet another Number Sequence(  矩阵快速幂  ) 题意: 就是矩阵快速幂,没什么好说的. 分析: 其实还是斐波那契数列.只是最后对应的矩阵不是(1,1)是(a,b)了 MOD = 1; for( int i = 0; i < m; ++i ) MOD *= 10; 代码 #include <cstdio> #include <cstring> #include <algorithm> using namespace s

ZOJ 2105 Number Sequence(矩阵快速幂)

题意: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. 给定A,B,求f(n). 法一: 网上较多的题解都提到了寻找1 1循环节的方法,的确非常巧妙,每位0~6,共7种可能,相邻两位共49种可能,因此循环周期至多为49,一旦出现相同数对,那么其后必相同.但是,该方法只是简单提及了49,却并没有证明1 1循环节一定存在,没有排除可能前面一段不循环,后面一段开始周期性循环的可能性.(是我悟性太差吗,为什么大多数题解都只谈

HDU4965-Fast Matrix Calculation(矩阵快速幂)

题目链接 题意:n*k的矩阵A和一个k*n的矩阵B,C = A * B.求M = (C)^(n * n)时,矩阵M中每个元素的和(每个元素都要MOD6) 思路:因为n最大到1000,所以不能直接用矩阵快速幂求AB的n*n次幂,但是可以将公式稍微转换下,M = AB * AB...* AB = A * (BA) *... * (BA) * B,这样BA的n*n -1次幂就能用矩阵快速幂求解,之后再分别乘以A,B即可. 代码: #include <iostream> #include <cs

数论基础——循环节和矩阵快速幂的运用

首先我们来看一道基础题: 题目链接:HDU1005 Number Sequence 题目描述: Number Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 147421    Accepted Submission(s): 35814 Problem Description A number sequence is