【JZOJ4798】天使的分裂

Description

这里写图片描述

Solution

我们把 Fn 化简。

Fn=ni=0fifni=ni=2(fi1+fi2)fni+f0fn+f1fn1

拆开得:
ni=2fi1fni+ni=2fi2fni+f0fn+f1fn1

现在我们要将求和的部分用 F 来表示。

我们设n1=n1n2=n2

对于第一部分: ni=2fi1fni ,我们把 i 1开始,那么原式变成: n1i=1fifn1i

然后我们逐步靠近 F 的式子,也就是把i变成 0 ,原式就变成了:
n1i=0fifn1if0fn1=Fn1f0fn1=Fn1f0fn1

然后处理第二部分: ni=2fi2fni = n2i=0fifn2i=Fn2=Fn2

然后整理一下可得: Fn1+Fn2f0fn1+f0fn+f1fn1

由于 f0=f1=1 ,所以化简可得 Fn1+Fn2fn1+fn+1=Fn1+Fn2+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];
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值