Codevs1732-矩阵乘法快速幂

Codevs1732,这道题要求求fibonacci数列的第N项,1 <= n <= 100000000000000,非常大,普通的O(N)的求法肯定会TLE,所以我们需要用的快速幂矩阵乘法,在O(logN)的时间内即可求出。
矩阵的乘法是这样的:
我们定义X(i,j)表示矩阵第i行第j列的元素。
我们定义两个矩阵A和B,A有n行m列,B有m行p列,则此时矩阵A和B的乘法有定义(当且仅当A的列数=B的行数时,A*B有定义):
A*B=C,矩阵C为n行p列 ,C(i,j)=Σ(A(i,k)*B(k,j)),1<=k<=m。矩阵的乘法可以这样用程序表达:

struct Matrix{
       qint A[10][10];
       int m,n;                //表示该矩阵有m行n列
       friend Matrix operator * (const Matrix a,const Matrix b){
              Matrix ret;
              ret.m=a.m,ret.n=b.n;
              for(int i=0;i<a.m;i++){
                      for(int j=0;j<b.n;j++){
                              ret.A[i][j]=0;
                              for(int k=0;k<b.m;k++){ret.A[i][j]=(ret.A[i][j]+a.A[i][k]*b.A[k][j])%MOD;}
                      }
              }
              return ret;
       }
};

矩阵的乘法有结合律但没有交换律,即(A*B)*C等于A*(B*C),但是A*B不等于B*A。由于矩阵的乘法支持结合律,所以可以利用快速幂的思想在O(logN)的时间内求出矩阵A ^ N。矩阵可以很好的表示线性递推关系。例如:
f(n)=a1*f(n-1) + a2*f(n-2) + ······ + ad*f(n-d),则我们可以设矩阵:
F(N)=|f(n-d+1) |  ( 共d行1列)
         |    ······   |
         |   f(n-1)  |
         |    f(n)    |                                                                    
我们再设矩阵A=
|0,1,0 ······ 0|
|0,0,1 ······ 0|
| ····················· |
|0,0,0 ······ 1|
|a1,a2,····ad|
(共d行d列),
则存在下列关系A*F(N-1)=F(N)。
于是我们就可以通过计算A的幂来快速求F(N)了。

贴一个codevs1732的标程:

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 using namespace std;
 5 typedef long long qint;
 6 const int MOD=1000000007;
 7 struct Matrix{
 8        qint A[10][10];
 9        int m,n;//m行n列的矩阵
10        friend Matrix operator * (const Matrix a,const Matrix b){
11               Matrix ret;
12               ret.m=a.m,ret.n=b.n;
13               for(int i=0;i<a.m;i++){
14                       for(int j=0;j<b.n;j++){
15                               ret.A[i][j]=0;
16                               for(int k=0;k<b.m;k++){
17                                       ret.A[i][j]=(ret.A[i][j]+a.A[i][k]*b.A[k][j])%MOD;
18                               }
19                       }
20               }
21               return ret;
22        }
23 };
24
25 int get_ans(qint n){
26     if(n<=1) return n;
27     n=n-1;
28     bool f=true;
29     Matrix st,now,pow;
30
31     st.A[0][0]=0,st.A[1][0]=1;
32     st.m=2,st.n=1;
33
34     pow.A[0][0]=0,pow.A[0][1]=1;
35     pow.A[1][0]=1,pow.A[1][1]=1;
36     pow.m=2,pow.n=2;
37
38     while(n>0){
39                if(n & 1){
40                     if(f){now=pow;f=false;}
41                     else{now=now*pow;}
42                }
43                pow=pow*pow;
44                n=n>>1;
45     }
46
47     now=now*st;
48     return now.A[1][0];
49 }
50
51
52
53 int main(){
54     qint n;
55     while(scanf("%lld",&n)!=EOF){
56             printf("%d\n",get_ans(n));
57     }
58
59     return 0;
60 }

1msAC,各种爽。

时间: 2024-12-14 14:29:22

Codevs1732-矩阵乘法快速幂的相关文章

快速求斐波那契数列(矩阵乘法+快速幂)

斐波那契数列 给你一个n:f(n)=f(n-1)+f(n-2) 请求出 f(f(n)),由于结果很大请 对答案 mod 10^9+7; 1<=n<=10^100; 用矩阵乘法+快速幂求斐波那契数列是经典应用: 矩阵公式 C i j=C i k *C k j; 根据递推式 构造2*2矩阵: 原始矩阵 1 0 0 1 矩阵 2 1 1 1 0 原始矩阵与矩阵 2相乘达到转化状态效果: 对矩阵二进行快速幂 乘法:达到快速转化矩阵的效果: 即使达到快速转化状态:那么大的数据范围也很难求解: 高精?这有

codevs1281 矩阵乘法 快速幂 !!!手写乘法取模!!! 练习struct的构造函数和成员函数

对于这道题目以及我的快速幂以及我的一节半晚自习我表示无力吐槽,, 首先矩阵乘法和快速幂没必要太多说吧,,嗯没必要,,我相信没必要,,实在做不出来写两个矩阵手推一下也就能理解矩阵的顺序了,要格外注意一些细节,比如快速幂时ans矩阵的初始化方式,快速幂的次数,矩阵乘法过程中对临时矩阵的清零,最后输出结果时的初始矩阵...矩阵快速幂好理解但是细节还是有点小坑的.. 下面就是满满的槽点,,高能慎入!!! 对于这个题目要求矩阵过程中对m取模,结果对g取模,我表示难以接受,,上来没看清题直接wa19个点,另

矩阵乘法快速幂 codevs 1732 Fibonacci数列 2

1732 Fibonacci数列 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 在“1250 Fibonacci数列”中,我们求出了第n个Fibonacci数列的值.但是1250中,n<=109.现在,你的任务仍然是求出第n个Fibonacci数列的值,但是注意:n为整数,且1 <= n <= 100000000000000 输入描述 Input Description 输入有多组数据,每

【BZOJ 2323】 2323: [ZJOI2011]细胞 (DP+矩阵乘法+快速幂*)

2323: [ZJOI2011]细胞 Description 2222年,人类在银河系外的某颗星球上发现了生命,并且携带了一个细胞回到了地球.经过反复研究,人类已经完全掌握了这类细胞的发展规律: 这种细胞最初的形态是"长条形",一端是头,一端是尾,中间是躯干.细胞内部含有一列密码(你可以认为它是这种细胞的DNA).密码是一个长度为n的数字串,且仅含有1~9这9种数字,沿着细胞的躯干从头到尾排列着. 首先,细胞会经历一次分裂.细胞将沿躯干方向分裂成若干个球体,躯干将退化成丝状物,连接着相

【bzoj3231】[Sdoi2008]递归数列 矩阵乘法+快速幂

题目描述 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai-k 其中bj和 cj (1<=j<=k)是给定的自然数.写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + ... + an, 并输出它除以给定自然数p的余数的值. 输入 由四行组成. 第一行是一个自然数k. 第二行包含k个自然数b1, b2,...,bk. 第三行包含k个自然数c1,

矩阵乘法快速幂 codevs 1574 广义斐波那契数列

codevs 1574 广义斐波那契数列 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 广义的斐波那契数列是指形如an=p*an-1+q*an-2的数列.今给定数列的两系数p和q,以及数列的最前两项a1和a2,另给出两个整数n和m,试求数列的第n项an除以m的余数. 输入描述 Input Description 输入包含一行6个整数.依次是p,q,a1,a2,n,m,其中在p,q,a1,a2整数范围内,n和m在长整数范围

【BZOJ-1009】GT考试 KMP+DP+矩阵乘法+快速幂

1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2745  Solved: 1694[Submit][Status][Discuss] Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2..

【bzoj4887】:[Tjoi2017]可乐 矩阵乘法,快速幂

[bzoj4887]:[Tjoi2017]可乐 题目大意:一张无相连通图(n<=30),从1号点开始走,每秒可以走到相邻的点也可以自爆,求第t秒(t<=1e6)后所有的方案数是多少对2017取模 恩..就是一个矩阵快速幂..矩阵就是原图的邻接矩阵..然后f[i][i]也是1.. 但是这是不会自爆的情况下的矩阵,算上自爆的话要把每次转移的结果求和..蒟蒻想了半天.. 然后发现其实只要再加一行一列,然后f[n+1][i]=1,就可以了.. 意会一下好了..矩阵什么的感觉讲不清楚啊.. 1 /* h

【矩阵乘法快速幂】

快速入门视频: av56433157 1> p1926 斐波那契 #include<cstdio> #include<cstdlib> #include<cstring> using namespace std; long long n; const int mod=1000000007; long long nw[2][2],ans[2][2]; long long t[2][2]; void mul1() { memset(t,0,sizeof(t)); fo

C++-POJ3735-Training little cats[矩阵乘法][快速幂]

矩阵快速幂,主要是考构造.另外,swap总是写龊? 为什么?干脆放弃了.唉,我太难了. 思路:操作e和s都很好想,主要是g操作 我们可以额外空出一位,记为1,每次要加1,就对这个额外的1进行计算即可 不妨定义A=[1 0 0 ... 0],此时只要构造一组操作的等效矩阵T就好了 就是添一位使初始矩阵A变为一个n+1元组,编号为0到n.以三只猫为例[1 0 0 0] 1 #include <cstdio> 2 typedef long long ll; 3 const int N=105; 4