【JZOJ4798】天使的分裂

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 来表示。

我们设n1=n−1,n2=n−2

对于第一部分: ∑ni=2fi−1fn−i ,我们把 i 从1开始,那么原式变成: ∑n1i=1fifn1−i 。

然后我们逐步靠近 F 的式子,也就是把i变成 0 ,原式就变成了:
∑n1i=0fifn1−i−f0fn1=Fn1−f0fn1=Fn−1−f0fn−1。

然后处理第二部分: ∑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];
}
posted @ 2016-09-24 15:17  sadstone  阅读(78)  评论(0)    收藏  举报