第二讲-乘方取模和矩阵快速幂

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

的n次
幂乘以初始矩阵
得到的结果就是

因为是2*2的据称,所以一次相乘的时间复杂度是O(2^3),总的复杂度是O(logn * 2^3 + 2*2*1)。

矩阵快速幂与斐波那契数列的关系
其实用的更多是使用矩阵快速幂,算递推式,注意是递推式,简单的如斐波那契 数列的第一亿项的结果模10000000后是多少你还能用递推式去,逐项递推吗? 当然不能,这里就可以发挥矩阵快速幂的神威了,那斐波那契数列和矩阵快速幂 能有一毛钱的关系?答案是有而且很大 斐波那契的定义是f(1)=f(2)=1; 然后f(n)=f(n-1)+f(n-2) (n>=2) 我们也可以这样定 义f(1)=f(2)=1; [f(n),f(n-1)]=[f(n-1),f(n-2)][1,1,1,0],其中[1,1,1,0] 是一个2*2的矩阵 上面一行是1,1,下面一行是1,0,这样就可以化简了写成[f(n),f(n1)]=[f(2),f(1)]*[1,1,1,0]^(n-2)
Leabharlann Baidu
解答:
return ans; } int main() { int n,t,s; scanf("%d",&t); while(t--) { scanf("%d",&n); s=PowerMod(n,n,10); printf("%d\n",s); } return 0; }
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cmath> #include<string> #include<algorithm> using namespace std; #define MA 10010 int PowerMod(int a,int b,int c) { int ans=1; a=a%c; while(b>0) { if(b&1) ans =(ans*a) % c; b=b>>1; a=(a*a)%c; }
#include <cstdio> #include <string> #include <cmath> #include <iostream> using namespace std; const long long M = 1000007; const long long N = 3; long long t,b,c,f1,f2; struct Node //矩阵 { long long line,cal; long long a[N+1][N+1]; Node() { line=3,cal=3; a[0][0] = b; a[0][1] = 1; a[0][2] = 0; a[1][0] = t; a[1][1] = 0; a[1][2] = 0; a[2][0] = c; a[2][1] = 0; a[2][2] = 1; } }; Node isit(Node x,long long c) //矩阵初始化 { for(long long i=0;i<N;i++) for(long long j=0;j<N;j++) x.a[i][j]=c; return x; }

例题:HDOJ1061
Problem Description Given a positive integer N, you should output the most right digit of N^N. Input The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow. Each test case contains a single positive integer N(1<=N<=1,000,000,000). Output For each test case, you should output the rightmost digit of N^N. Sample Input 2 3 4 Sample Output 7 6

例题:HDOJ1005
A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. Given A, B, and n, you are to calculate the value of f(n). Input The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed. Output For each test case, print the value of f(n) on a single line. Sample Input 113 1 2 10 000 Sample Output 2 5

作业:
HDOJ:1060、1061、2035、1005、2068
7月19日

解答:(公式法)
#include<stdio.h> #include<string.h> int main() { int a,b,n,i; while(~scanf("%d%d%d",&a,&b,&n)) { if(a==0&&b==0&&n==0) break; int f[1009]; f[1]=1;f[2]=1; for(i=3;i<=1008;i++) f[i]=(a*f[i-1]+b*f[i-2])%7; printf("%d\n",f[(n-1)%1008+1]); } return 0; }

解答:(矩阵快速幂法)
#include<math.h> #include<string.h> #include<iostream> #include<stdio.h> #include<stdlib.h> #define inf 0x3f3f3f using namespace std; struct mat { int matrix[2][2]; };typedef struct mat Matrix; Matrix mul(Matrix a,Matrix b) { Matrix result; result.matrix[0][0] = ( a.matrix[0][0]*b.matrix[0][0] + a.matrix[0][1]*b.matrix[1][0] )%7; result.matrix[0][1] = ( a.matrix[0][0]*b.matrix[0][1] + a.matrix[0][1]*b.matrix[1][1] )%7; result.matrix[1][0] = ( a.matrix[1][0]*b.matrix[0][0] + a.matrix[1][1]*b.matrix[1][0] )%7; result.matrix[1][1] = ( a.matrix[1][0]*b.matrix[0][1] + a.matrix[1][1]*b.matrix[1][1] )%7; return result; } void qsm(int p,int q,int n) { Matrix c,d; c.matrix[0][0] = 1;d.matrix[0][0] = p; c.matrix[0][1] = 0;d.matrix[0][1] = q; c.matrix[1][0] = 0;d.matrix[1][0] = 1; c.matrix[1][1] = 1;d.matrix[1][1] = 0; while(n) { if(n & 1) c = mul(c,d); n>>=1; d = mul(d,d); } printf("%d\n",(c.matrix[1][0]+c.matrix[1][1])%7); } int main() { int s,p,q,n; while(scanf("%d%d%d",&p,&q,&n) && p+q+n != 0) qsm(p,q,n-1); return 0; }
二、矩阵快速幂
定义: 若A是一个矩阵,那么求A的n次方的过程就是矩 阵快速幂 引入:

举个例子: 求第n个Fibonacci数模M的值。如果这个n非常大的话,普通的递推时间复杂度为 O(n),这样的复杂度很有可能会挂掉。这里可以用矩阵做优化,复杂度可以降到 O(logn * 2^3) 如图
A = F(n - 1), B = F(n - 2),这样使构造矩阵
第二讲:
乘方取模和矩阵快速幂
詹海艳
一、乘方取模问题

二分思想:
a n%m=

a
n 2
%m
2
2
n为偶数
a
n 2
%m a%m
n为奇数
注:把时间复杂度从O(n)降为O(logn)了

快速幂取余: m^n % k模板 int quickpow(int m,int n,int k) { int b = 1; while (n > 0) { if (n & 1) b = (b*m)%k; n = n >> 1 ; m = (m*m)%k; } return b; }
简单描述:[f(n),f(n-1)]=[f(n-1),f(n-2)] X
1 1
1 0
这样就可以用矩阵快速幂,快速的推出斐波那契数列的第一亿项的值了(当然是 取模的值了)是不是很神奇,类似的递推式也可以,化成这种形式,用矩阵快速 幂进行计算

矩阵快速幂模板:
Node Matlab(Node x,Node s) //矩阵乘法 { Node ans; ans.line = x.line,ans.cal = s.cal; ans=isit(ans,0); for(long long i=0;i<x.line;i++) { for(long long j=0;j<x.cal;j++) { for(long long k=0;k<s.cal;k++) { ans.a[i][j] += x.a[i][k]*s.a[k][j]; ans.a[i][j]=(ans.a[i][j]+M)%M; } } } return ans; } long long Fast_Matrax(long long n) //矩阵 快速幂 { if(n==1) return f1; n-=2; long long x=1,f=n,ok=1; Node ans,tmp,ch; ans.line = 1,ans.cal = 3; ans.a[0][0] = f2, ans.a[0][1] = f1 ,ans.a[0][2] = 1; while(n>0) { if(n%2) ans=Matlab(ans,tmp); tmp=Matlab(tmp,tmp); n/=2; } return ans.a[0][0]; } int main() { long long n,T; scanf("%lld",&T); while(T--) { scanf("%lld%lld%lld%lld%lld% lld",&f1,&f2,&t,&b,&c,&n); printf("%lld\n",Fast_Matrax(n)) ; } return 0; }
相关文档
最新文档