蓝桥杯 算法提高 递推求值
题目如下:
问题描述
已知递推公式:
F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5,
F(n, 2)=F(n-1, 1) + 3F(n-3, 1) + 2F(n-3, 2) + 3.
初始值为:F(1, 1)=2, F(1, 2)=3, F(2, 1)=1, F(2, 2)=4, F(3, 1)=6, F(3, 2)=5。
输入n,输出F(n, 1)和F(n, 2),由于答案可能很大,你只需要输出答案除以99999999的余数。
F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5,
F(n, 2)=F(n-1, 1) + 3F(n-3, 1) + 2F(n-3, 2) + 3.
初始值为:F(1, 1)=2, F(1, 2)=3, F(2, 1)=1, F(2, 2)=4, F(3, 1)=6, F(3, 2)=5。
输入n,输出F(n, 1)和F(n, 2),由于答案可能很大,你只需要输出答案除以99999999的余数。
输入格式
输入第一行包含一个整数n。
输出格式
输出两行,第一行为F(n, 1)除以99999999的余数,第二行为F(n, 2)除以99999999的余数。
样例输入
4
样例输出
14
21
21
数据规模和约定
1<=n<=10^18。
-----分割线-----
在拿到此题后,就知道这题应该是矩阵快速幂,但是因为以前只做过简单的斐波那契数列的矩阵快速幂,所以完全不知道这题该怎么构造矩阵,后来翻了百度上的很多博客。简单来说,就是找到一个矩阵A满足:x(n-1)*A=x(n)。当然,此题不同于一般的“x(n)、x(n-1)”。要做如下构造:
[f(n-1,1),f(n-1,2),f(n-2,1),f(n-2,2),f(n-3,1),f(n-3,2),5,3]*A=[f(n,1),f(n,2),f(n-1,1),f(n-1,2),f(n-2,1),f(n-2,2),5,3]
即把前三项当做x(n-1),后一项以及前三项的后两项当做x(n),易知矩阵为8阶矩阵,具体见代码:
#include<stdio.h> #define max 99999999 #define ll long long int typedef struct Matrix { ll m[8][8]; }mat; mat multi(mat x,mat y,int a,int b,int c) { int i,j,k; mat z; for(i=0;i<8;i++) for(j=0;j<8;j++) z.m[i][j]=0; for(i=0;i<a;i++) for(j=0;j<c;j++) for(k=0;k<b;k++) z.m[i][j]=(z.m[i][j]+(x.m[i][k]*y.m[k][j])%max)%max; return z; } int main() { ll n,v1,v2,i; mat A={ 0,1,1,0,0,0,0,0, 1,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0, 0,0,0,0,0,1,0,0, 2,3,0,0,0,0,0,0, 0,2,0,0,0,0,0,0, 1,0,0,0,0,0,1,0, 0,1,0,0,0,0,0,1 }; mat E={ 1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0, 0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0, 0,0,0,0,0,1,0,0, 0,0,0,0,0,0,1,0, 0,0,0,0,0,0,0,1, }; ll s[8]={6,5,1,4,2,3,5,3}; scanf("%I64d",&n); if(n==1) printf("2\n3"); if(n==2) printf("1\n4"); if(n==3) printf("6\n5"); if(n>=4) { n-=3; while(n) { if(n%2) E=multi(E,A,8,8,8); n/=2; A=multi(A,A,8,8,8); } v1=0; v2=0; for(i=0;i<8;i++) { v1=(v1+(s[i]*E.m[i][0])%max)%max; v2=(v2+(s[i]*E.m[i][1])%max)%max; } printf("%I64d\n%I64d",v1,v2); } return 0; }