题解 [51nod1358] 浮波那契
题解 [51nod1358] 浮波那契
题面
解析
首先根据经验应该能一眼矩阵快速幂加速....
因为给了你递推式,并且\(O(n)\)求显然不可能.
所以考虑怎么构造矩阵.
首先要处理的是小数的问题,
这里我们可以把\(n\)扩大5倍,
那么就变成了
\[\begin{equation}f(n)=\left\{ \begin{array}{**lr**} 1 ,n\leq20 & \\ f(n-5)+f(n-17),otherwise \end{array}\right.\end{equation}
\]
然后考虑怎么构造矩阵,
想一想,一开始矩阵应该是这个样子:
\[\left[
\begin{matrix}
f(n-1)&f(n-2)&\dots&f(n-17)
\end{matrix}
\right]
\]
乘上一个矩阵得到
\[\left[\begin{matrix}f(n)&f(n-1)\dots&f(n-16)\end{matrix}\right]
\]
然后因为有重复的项我们就设为\(1\),再把递推的地方设为\(1\),其它地方设为\(0\).
讲的太不清楚了还是直接看矩阵吧
\[\left[\begin{matrix}01000000000000000&\\00100000000000000&\\00010000000000000&\\00001000000000000&\\10000100000000000&\\00000010000000000&\\00000001000000000&\\00000000100000000&\\00000000010000000&\\00000000001000000&\\00000000000100000&\\00000000000010000&\\00000000000001000&\\00000000000000100&\\00000000000000010&\\00000000000000001&\\10000000000000000&\\\end{matrix}\right]
\]
实际上结合矩阵乘法想一想应该就行了.
接下来直接跑矩阵快速幂即可.
code:
#include <iostream>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;
inline int read(){
int sum=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
return f*sum;
}
const int N=101;
const int Mod=1000000007;
struct mat{
ll f[N][N];
inline void clear(){memset(f,0,sizeof f);}
inline void init(){clear();for(int i=0;i<N;i++) f[i][i]=1;}
}a,b;
ll n;
inline mat operator*(mat a,mat b){
mat c;c.clear();
for(int k=0;k<17;k++){
for(int i=0;i<17;i++){
ll t=a.f[i][k];
for(int j=0;j<17;j++) c.f[i][j]=(c.f[i][j]+t*b.f[k][j])%Mod;
}
}
return c;
}
inline mat fpow(mat a,ll b){
mat ret;ret.init();
for(;b;a=a*a,b>>=1) if(b&1) ret=ret*a;
return ret;
}
signed main(){
n=read();
if(n<=4){puts("1");return 0;}
for(int i=0;i<17;i++) a.f[0][i]=1;
for(int i=0;i<16;i++) b.f[i][i+1]=1;
b.f[4][0]=1;b.f[16][0]=1;
a=a*fpow(b,n*5-20);
printf("%lld\n",a.f[0][0]);
return 0;
}