洛谷1349 广义斐波那契数列
题目描述
广义的斐波那契数列是指形如an=p*an-1+q*an-2的数列。今给定数列的两系数p和q,以及数列的最前两项a1和a2,另给出两个整数n和m,试求数列的第n项an除以m的余数。
输入输出格式
输入格式:
输入包含一行6个整数。依次是p,q,a1,a2,n,m,其中在p,q,a1,a2整数范围内,n和m在长整数范围内。
输出格式:
输出包含一行一个整数,即an除以m的余数。
输入输出样例
输入样例#1:
1 1 1 1 10 7
输出样例#1:
6
说明
数列第10项是55,除以7的余数为6。
【思路】
矩阵乘法。
n最大为maxlongint所以枚举肯定会有TLE。
这里用到了矩阵乘法。大体思想:因为每次的求解规则相同,所以可以构造一个转移矩阵,使得每个点与该矩阵相乘即可直接得出最终该点的位置。
开始矩阵B:
a2 a1
构造矩阵如下:
P 1
Q 0
(一次转换后为
p*a2+q*a1,a2 )
因为要进行n-2次相同的转换所以用快速幂求解转换n-2次后的A’ 。
ans=B*A‘
注意: 矩阵乘法的顺序不能更改,否则可能不满足乘法要求。
LL 与 LL的乘法可能会爆精度,可以转化为小数相加的形式。
代码思想源于洛谷题解。
【代码】
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 typedef long long LL; 6 const int delen=23,delta=1<<23,deltb=delta-1; 7 LL n,m,p,q,a1,a2; 8 9 LL Add(LL x,LL y) { 10 x+=y; 11 if(x>=m) x-=m; 12 return x; 13 } 14 15 LL multi(LL x,LL y) { //对于long long型的 乘法+模 防止越界 16 LL ans=0; 17 while(y) { 18 if(y&deltb) ans=Add(ans,x*(y&deltb)%m); 19 x=x*delta%m; 20 y>>=delen; 21 } 22 return ans; 23 } 24 25 struct Matrix{ 26 int r,c; 27 LL N[5][5]; 28 Matrix operator *(const Matrix& rhs) const{ 29 Matrix tmp={}; 30 tmp.r=r, tmp.c=rhs.c; 31 for(int i=0;i<tmp.r;i++) 32 for(int j=0;j<tmp.c;j++) { 33 for(int k=0;k<c;k++) tmp.N[i][j] += multi(N[i][k],rhs.N[k][j]); 34 tmp.N[i][j] %= m; 35 } 36 return tmp; 37 } 38 39 Matrix pow(LL p) const{ 40 Matrix ans={} , tmp=*this; 41 ans.r=ans.c=r; 42 for(int i=0;i<r;i++) ans.N[i][i]=1; 43 while(p) { 44 if(p&1) ans=ans*tmp; 45 tmp=tmp*tmp; 46 p>>=1; 47 } 48 return ans; 49 } 50 }; 51 52 int main() { 53 cin>>p>>q>>a1>>a2>>n>>m; 54 Matrix A,B; 55 A.r=A.c=2; 56 A.N[0][0]=p , A.N[1][0]=q , A.N[0][1]=1 , A.N[1][1]=0; //0 57 A=A.pow(n-2); 58 59 B.r=1 , B.c=2; 60 B.N[0][0]=a2,B.N[0][1]=a1; 61 62 B=B*A; //B*A 63 64 cout<<B.N[0][0]%m; 65 return 0; 66 }
时间: 2024-10-13 00:43:02