题解 [51nod1358] 浮波那契
题面
解析
首先根据经验应该能一眼矩阵快速幂加速....
因为给了你递推式,并且(O(n))求显然不可能.
所以考虑怎么构造矩阵.
首先要处理的是小数的问题,
这里我们可以把(n)扩大5倍,
那么就变成了
[egin{equation}f(n)=left{ egin{array}{**lr**} 1 ,nleq20 & \ f(n-5)+f(n-17),otherwise end{array}
ight.end{equation}
]
然后考虑怎么构造矩阵,
想一想,一开始矩阵应该是这个样子:
[left[
egin{matrix}
f(n-1)&f(n-2)&dots&f(n-17)
end{matrix}
ight]
]
乘上一个矩阵得到
[left[egin{matrix}f(n)&f(n-1)dots&f(n-16)end{matrix}
ight]
]
然后因为有重复的项我们就设为(1),再把递推的地方设为(1),其它地方设为(0).
讲的太不清楚了还是直接看矩阵吧
[left[egin{matrix}01000000000000000&\00100000000000000&\00010000000000000&\00001000000000000&\10000100000000000&\00000010000000000&\00000001000000000&\00000000100000000&\00000000010000000&\00000000001000000&\00000000000100000&\00000000000010000&\00000000000001000&\00000000000000100&\00000000000000010&\00000000000000001&\10000000000000000&\end{matrix}
ight]
]
实际上结合矩阵乘法想一想应该就行了.
接下来直接跑矩阵快速幂即可.
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
",a.f[0][0]);
return 0;
}