Accepted极限代码巅峰赛 E Triangle

题目


题解

神奇题

定义题目要求的“合法序列”为 \(a_i \in [1,n],\; a_i+a_{i+1}\le a_{i+2}\)

定义长为l的斐波那契序列\(Fib_l\)为序列 \(\{fib_1,fib_2,\cdots, fib_l\}\)

定义两个数列的和为右对齐然后按位相加(不足补0),如 \(\{1,2,3\}+\{3,4\}=\{1,5,7\}\)

定义斐波那契序列组为若干斐波那契序列,如 \(\{\{1\},\{1,1,2\},\{1,1,2,3,5\}\}\)


重要结论:斐波那契序列组 与 合法序列 关于 \(\varphi=\)数列求和 构成双射

证明:

首先证明单射。反证,若不是单射,则存在两个斐波那契序列组S1,S2,二者和相同
记和的长度为l,因为长为l的斐波那契序列唯一,所以可以从S1,S2中提出相同数量的\(Fib_l\);如此类推,得S1=S2,矛盾

其次证明满射,任意一个合法序列都对应至少一个斐波那契序列组
记序列长度为l,则不断从合法序列中减去\(Fib_l\),则限制变为 \(a_i-fib_i+a_{i+1}-fib_{i+1}\le a_{i+2}-fib_{i+2}\) ,仍满足,因此减去之后仍是合法序列,直到全为0;此时就得到了一个斐波那契序列组

例子:\(\{1\}+\{1,1,2\}+\{1,1,2,3,5\}=\{1,1,3,4,8\}\)

因此问题变成了统计所有斐波那契序列组的答案,而斐波那契序列组又是若干斐波那契序列之和

\(f_{l,i}\)表示长度最多为l,结尾为i的答案,每次往里面加一个\(Fib_l\)做完全背包即可

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (int a=b; a<=c; a++)
#define fd(a,b,c) for (int a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%mod
#define mod 998244353
#define Mod 998244351
#define ll long long
#define file
using namespace std;

const int N=1e6+10;
int n,m,T;
ll f[N],ans;
int fib[31],prodfib[31];

void solve()
{
    scanf("%d%d",&n,&m);
    fib[1]=fib[2]=1;
    prodfib[1]=prodfib[2]=m;
    fo(i,3,30)
    {
		fib[i]=fib[i-1]+fib[i-2];
		prodfib[i]=1ll*prodfib[i-1]*prodfib[i-2]%mod;
	}
	fo(i,2,30) prodfib[i]=1ll*prodfib[i-1]*prodfib[i]%mod;
    
    f[0]=1;
    fo(l,1,30)
    {
    	fo(i,fib[l],n)
    	add(f[i],f[i-fib[l]]*prodfib[l]);
	}
    
    fo(i,1,n) add(ans,f[i]);
    printf("%lld\n",(ans+mod)%mod);
}

int main()
{
//	freopen("E.in","r",stdin);

    T=1;
    //scanf("%d",&T);
    for (;T;--T) solve();
	
    return 0;
}
posted @ 2024-11-06 20:59  gmh77  阅读(49)  评论(0编辑  收藏  举报