Buge's Fibonacci Number Problem
题意:
数据范围:
Each test case contains 7 integers, they are f1, f2, a, b, k, n, m which were just mentioned above, where 0 < f1, f2, a, b, n, m < 1000 000 000, and 0 ≤ k < 50.
题解:对于这种k次方,而且累加求和的一般都是矩阵快速幂,只要是构造矩阵比较麻烦。
看一个大神的题解(侵删):
本题要二项式展开,别怕麻烦。
扫描二维码关注公众号,回复:
999964 查看本文章
![](/qrcode.jpg)
方法和以前的矩阵推法一样,就是矩阵是变化的,根据数据而变化。
先自己写下,感觉纸写不下时,就别写了!
设k=3;自己展开算一下:
右边的展开: 就是用f(n)=af(n-1)+bf(n-2) 把f(n)都换成 f(n-1)f(n-2)的表达式,最后根据表达式把上面左边的矩阵求出。惊奇的发现很有规律,是个下三角矩阵,和k有直接的关系。
是k+2的方阵。设该方阵为A,则 (A*F). a11=s(2);所以只要计算 n-1次,就能算出s(n)了。
注意:s(1)不等于f1, s(1)=f1^k,我在这里WA 了20次,低级错误!
所以当k>3时,矩阵也推出来了。
就是二项式的展开作为系数的下三角矩阵。
如何解决矩阵的大小不固定问题:
想了很多,想用类,或用指针,走了弯路!
突然想到,初始化开1个很大的2维数组,然后每次矩阵乘法时根据每组数据的矩阵的维数来计算就行了,实际运行时正确的,测试很多回了,基本没改动模板,看代码就懂了。
#include <iostream> #include <stdio.h> #include <string.h> #define LL long long using namespace std; const int maxn=50; LL mod,k,K; struct Mat { LL mp[maxn+10][maxn+10]; } res,A; LL C[maxn+10][maxn+10]; LL line[maxn+10]; void get_C() { C[0][0]=1; for(int i=1; i<=maxn; ++i) { C[i][0]=1; for(int j=1; j<=i; ++j) C[i][j]=(C[i-1][j]+C[i-1][j-1]); } } LL _pow(LL x,LL y) { LL ans=1; while(y>0) { if(y&1) ans=ans*x%mod; x=x*x%mod; y/=2; } return ans; } Mat Mul(Mat a,Mat b) { Mat c; memset(c.mp,0,sizeof(c.mp)); for(LL kk=0; kk<k; ++kk) for(LL i=0; i<k; ++i) { if(a.mp[i][kk]==0) continue; for(LL j=0; j<k; ++j) c.mp[i][j]=(c.mp[i][j]+(a.mp[i][kk]*b.mp[kk][j]%mod))%mod; } return c; } LL Cal(LL y) { while(y>0) { if(y&1) res=Mul(res,A); y/=2; A=Mul(A,A); } LL ans=0; for(LL i=0; i<k; ++i) { ans=(ans+res.mp[0][i]%mod*line[i]%mod)%mod; } return ans; } int main() { get_C(); LL f1,f2,a,b,n; int T; scanf("%d",&T); while(T--) { scanf("%lld %lld %lld %lld %lld %lld %lld",&f1,&f2,&a,&b,&k,&n,&mod); K=k; k=k+2; memset(res.mp,0,sizeof(res.mp)); for(LL i=0; i<k; ++i) res.mp[i][i]=1; memset(A.mp,0,sizeof(A.mp)); A.mp[0][0]=A.mp[0][k-1]=1; int r=0,l; for(LL i=1; i<k; ++i) { l=0; for(LL j=k-i; j<k; ++j) { A.mp[i][j]=(C[r][l]%mod*_pow(a,l)%mod*_pow(b,r-l))%mod; l++; } r++; } line[0]=_pow(f1,K)%mod; l=0; for(LL i=1; i<k; ++i) { line[i]=_pow(f2,l)%mod*_pow(f1,K-l)%mod; l++; } printf("%lld\n",Cal(1ll*(n-1))); } return 0; }
具体的文件传在网上了 链接:http://pan.baidu.com/s/1slJk169 密码:38j8