矩阵初学
矩阵是个非常神奇的东西,矩阵+,-,*,倒置 等基本运算
然后我们能用矩阵干什么呢?
556. Fibonacci数列
(降低递推问题的时间复杂度)
题目描述
定义:f0=f1=1, fn=fn-1+fn-2(n>=2)。{fi}称为Fibonacci数列。
输入n,求fn mod q。其中1<=q<=30000。
输入描述
第一行一个数T(1<=T<=10000)。 以下T行,每行两个数,n,q(n<=10^9, 1<=q<=30000)
输出描述
文件包含T行,每行对应一个答案。
样例输入
3
6 2
7 3
7 11
样例输出
1
0
10
数据范围及提示
1<=T<=10000
n<=10^9, 1<=q<=30000
分析一下就是简单的 fibonacci
但普通方法是O(n)的显然不够,我们想优化
发现f[n]只和f[n-1],f[n-2]有关系
那我们就可以避免中间复杂的无用项的计算,
想想矩阵,怎么构造乘法关系让加法递推变成乘法递推
【 f[1] , f[2] 】*【 0 , 1 =【 f[2] , f[3] 】
1 , 1 】
然后数学归纳发现可以,于是快速幂
ac:但是有些地方写的有点麻烦
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> #define LL long long using namespace std; template<typename T> inline void read(T &a){ a=0;bool b=0;char x=getchar(); while(x<'0'||'9'<x){ if(x=='-')b=1; x=getchar(); } while('0'<=x&&x<='9'){ a=(a<<1)+(a<<3)+x-'0'; x=getchar(); } if(b)a=-a; } char C_[50]; int TEMP; template <typename T> inline void write(T a){ if(a<0){ putchar('-'); a=-a; } do{ C_[++TEMP]=a%10+'0'; a/=10; }while(a); while(TEMP)putchar(C_[TEMP--]); } int n,t,q; struct Sq{ int num[5][5],n,m; Sq(){ num[1][1]=num[1][2]=num[2][1]=num[2][2]=0; } Sq operator *(const Sq &a){ Sq ans; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) for(int k=1;k<=m;k++){ ans.num[i][j]=(ans.num[i][j]+num[i][k]*a.num[k][j])%q; } ans.n=ans.m=m; return ans; } void Get_E(int N){ n=m=N; for(int i=1;i<=N;i++)num[i][i]=1; } void F_init(){ n=m=2; num[1][1]=0; num[1][2]=num[2][1]=num[2][2]=1; } }; inline Sq quickpow(Sq a,int n){ Sq ans; ans.Get_E(2); while(n){ if(n&1)ans=ans*a; a=a*a; n>>=1; } return ans; } int main(){ read(t); while(t--){ read(n); read(q); Sq a; a.F_init(); Sq b=quickpow(a,n); write((b.num[1][1]+b.num[2][1])%q);putchar('\n'); } return 0; }