Description
Solution
我们把 Fn 化简。
Fn=∑ni=0fifn−i=∑ni=2(fi−1+fi−2)fn−i+f0fn+f1fn−1
拆开得:
∑ni=2fi−1fn−i+∑ni=2fi−2fn−i+f0fn+f1fn−1
现在我们要将求和的部分用 F 来表示。
我们设
对于第一部分:
∑ni=2fi−1fn−i
,我们把
i
从
然后我们逐步靠近
F
的式子,也就是把
然后处理第二部分: ∑ni=2fi−2fn−i = ∑n2i=0fifn2−i=Fn2=Fn−2
然后整理一下可得: Fn−1+Fn−2−f0fn−1+f0fn+f1fn−1
由于 f0=f1=1 ,所以化简可得 Fn−1+Fn−2−fn−1+fn+1=Fn−1+Fn−2+fn
我们发现递推式出来了。可这样的时间复杂度是 O(n) 的。
不虚,我们有矩阵乘法。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define mo 998244353
#define ll long long
#define N 7
using namespace std;
ll a[N]={0,1,1,2,1,3,1};
ll z[N][N]=
{
{0},
{0,1,1,1,0,1},
{0,1,0,1,0,1},
{0,0,0,1,1,1},
{0,0,0,1,0,1},
{0,0,0,0,0,1},
};
ll b[N][N],c[N][N];
void mul(ll p[N][N],ll q[N][N])
{
memset(c,0,sizeof(c));
fo(i,1,N-1)
fo(j,1,N-1)
fo(k,1,N-1)
c[i][j]=(c[i][j]+p[i][k]*q[k][j]%mo)%mo;
memcpy(p,c,sizeof(c));
}
void pow(ll n)
{
fo(i,1,N-1) b[i][i]=1;
while(n)
{
if(n%2) mul(b,z);
n/=2;
mul(z,z);
}
}
ll as[N];
int main()
{
ll n;
cin>>n;
if(n<2)
{
cout<<a[n+4];
return 0;
}
pow(n-1);
fo(j,1,N-1)
fo(k,1,N-1)
as[j]=(as[j]+a[k]*b[k][j]%mo)%mo;
cout<<as[5];
}