题解 19CSP-S十一集训三地联考—众神归位 A. 【十一·联考】幸福

幸 福 \color{blue}{幸福}

Time Limit: 1SMemory Limit: 256MB
Total Submissions: 652Accepted: 111

D e s c r i p t i o n \color{blue}{Description} Description
在只有纯白的世界里,栋栋和糯糯开始构建世界的色彩。

在第 0 0 0 天,他们相爱并创造了一颗爱心,这颗爱心由栋栋拿着。

接下来的每一天,栋栋和糯糯都将手里的爱心全部递给对方,然后栋栋会再从手中再生出与其今天给出的相同数量的爱心。

即,若令第 ii 天的栋栋手里爱心的数目为 f i f_i fi,那么 f f f 满足 f 0 = 1 , f 1 = 1 , f i = f i − 1 + f i − 2 ( i > 1 ) f_0=1,f_1=1,f_i=f_{i−1}+f_{i−2}(i>1) f0=1,f1=1,fi=fi1+fi2(i>1)

不断再生并相互传递爱心会产生幸福,栋栋的幸福度被认为是其每天手里的爱心数的一个卷积,即 F n = ∑ i = 0 n f i f n − i F_n=∑^n_{i=0}f_if_{n−i} Fn=i=0nfifni

本是一成不变的风景中,两人逐渐被越来越多的爱心围绕。糯糯想要知道,从第 0 0 0 天到第 n n n天栋栋一共收获了多少幸福呢?即要求你计算 ∑ i = 0 n F i ∑_{i=0}^nF_i i=0nFi 。由于栋栋肯定很幸福,答案也可能很大,她只需要你将答案对 998244353 998244353 998244353 取模。

I n p u t \color{blue}{Input} Input
一行,一个整数 n n n

O u t p u t \color{blue}{Output} Output
一行,一个整数,表示第 0 0 0 天到第 n n n 天的栋栋的幸福度的和。

S a m p l e   I n p u t \color{blue}{Sample\ Input} Sample Input
5

S a m p l e   O u t p u t \color{blue}{Sample\ Output} Sample Output
76


推一下公式:
F n = ∑ i = 0 n f i f n − i F_n=\sum_{i=0}^{n}f_if_{n-i} Fn=i=0nfifni
       = f 0 f n + f 1 f n − 1 + ∑ i = 2 n f i f n − i \ \ \ \ \ \ =f_0f_n+f_1f_{n-1}+\sum_{i=2}^nf_if_{n-i}       =f0fn+f1fn1+i=2nfifni
       = f 0 f n + f 1 f n − 1 + ∑ i = 2 n ( f i − 1 + f i − 2 ) f n − i \ \ \ \ \ \ =f_0f_n+f_1f_{n-1}+\sum_{i=2}^n(f_{i-1}+f_{i-2})f_{n-i}       =f0fn+f1fn1+i=2n(fi1+fi2)fni
       = f 0 f n + f 1 f n − 1 + ∑ i = 2 n ( f i − 1 f n − i + f i − 2 f n − i ) \ \ \ \ \ \ =f_0f_n+f_1f_{n-1}+\sum_{i=2}^n{(f_{i-1}f_{n-i}+f_{i-2}f_{n-i})}       =f0fn+f1fn1+i=2n(fi1fni+fi2fni)
       = f 0 f n + f 1 f n − 1 + ∑ i = 2 n f i − 1 f n − i + ∑ i = 2 n f i − 2 f n − i \ \ \ \ \ \ =f_0f_n+f_1f_{n-1}+\sum_{i=2}^n{f_{i-1}f_{n-i}}+\sum_{i=2}^{n}{f_{i-2}f_{n-i}}       =f0fn+f1fn1+i=2nfi1fni+i=2nfi2fni
       = f 0 f n + f 1 f n − 1 + ∑ i = 1 n f i f n − i − 1 + ∑ i = 0 n f i f n − i − 2 \ \ \ \ \ \ =f_0f_n+f_1f_{n-1}+\sum_{i=1}^n{f_{i}f_{n-i-1}}+\sum_{i=0}^{n}{f_{i}f_{n-i-2}}       =f0fn+f1fn1+i=1nfifni1+i=0nfifni2
       = f 0 f n + f 1 f n − 1 + ∑ i = 0 n f i f n − i − 1 − f 0 f n − i + ∑ i = 2 n f i − 2 f n − i \ \ \ \ \ \ =f_0f_n+f_1f_{n-1}+\sum_{i=0}^n{f_{i}f_{n-i-1}}-f_0f_{n-i}+\sum_{i=2}^{n}{f_{i-2}f_{n-i}}       =f0fn+f1fn1+i=0nfifni1f0fni+i=2nfi2fni
       = f 0 f n + ∑ i = 0 n f i f n − i − 1 + ∑ i = 2 n f i − 2 f n − i \ \ \ \ \ \ =f_0f_n+\sum_{i=0}^n{f_{i}f_{n-i-1}}+\sum_{i=2}^{n}{f_{i-2}f_{n-i}}       =f0fn+i=0nfifni1+i=2nfi2fni
       = F n − 1 + F n − 2 + f n \ \ \ \ \ \ =F_{n-1}+F_{n-2}+f_n       =Fn1+Fn2+fn

然后用矩阵快速幂实现即可:
( f n f n + 1 F n F n + 1 ∑ i = 0 n F ) = ( 0 1 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 ) × ( f n − 1 f n F n − 1 F n ∑ i = 0 n − 1 F ) = ( 0 1 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 ) n × ( 1 1 1 2 1 ) \begin{pmatrix} f_n \\ f_{n+1} \\ F_n \\ F_{n+1}\\ \sum_{i=0}^nF\\ \end{pmatrix}= \begin{pmatrix} 0&1&0&0&0\\ 1&1&0&0&0\\ 0&0&0&1&0\\ 1&1&1&1&0\\ 0&0&0&1&1\\ \end{pmatrix}\times \begin{pmatrix} f_{n-1} \\ f_{n} \\ F_{n-1} \\ F_{n}\\ \sum_{i=0}^{n-1}F\\ \end{pmatrix}= \begin{pmatrix} 0&1&0&0&0\\ 1&1&0&0&0\\ 0&0&0&1&0\\ 1&1&1&1&0\\ 0&0&0&1&1\\ \end{pmatrix}^{n}\times \begin{pmatrix} 1\\ 1\\ 1\\ 2\\ 1\\ \end{pmatrix} fnfn+1FnFn+1i=0nF=0101011010000100011100001×fn1fnFn1Fni=0n1F=0101011010000100011100001n×11121
代码实现如下:

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int mod=998244353;

struct maxtri
{
	ll a[10][10];
	maxtri() {memset(a,0,sizeof(a));}
	void build()
	{
		for(int i=1;i<=5;++i)
			a[i][i]=1;
	}
};

maxtri operator *(const maxtri &x,const maxtri &y)
{
	maxtri res;
	for(int k=1;k<=5;++k)
		for(int i=1;i<=5;++i) if(x.a[i][k]!=0)
			for(int j=1;j<=5;++j)
				res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
	return res;
}

maxtri fpow(maxtri a,ll k)
{
	maxtri res; res.build();
	while(k)
	{
		if(k&1) res=res*a;
		a=a*a;
		k>>=1;
	}
	return res;
}

int main()
{
//	freopen("input.txt","r",stdin);
	ll n; scanf("%lld",&n);
    maxtri ans,base;
    ans.a[1][1]=1; ans.a[2][1]=1; ans.a[3][1]=1; ans.a[4][1]=2; ans.a[5][1]=1;
    base.a[1][2]=base.a[2][1]=base.a[2][2]=base.a[3][4]=base.a[4][1]=base.a[4][2]=base.a[4][3]=base.a[4][4]=base.a[5][4]=base.a[5][5]=1;
    ans=fpow(base,n)*ans;
    printf("%lld",ans.a[5][1]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值