显然的,一个优秀数列对应的所有良好数列,每一种数的数量都是相同的。考虑借助这一点进行 \(dp\)。
那么容易想到 \(dp\) 的三个维度:枚举到第 \(i\) 种数,目前已经加入了 \(j\) 个数,目前有 \(l\) 种良好数列。但是这根本无法转移,考虑进一步发掘性质。我们先做一个定义:
定义 准良好数列 为相邻两项差的绝对值 \(\le 1\) 且首项最小的数列。
那么 显然一个没有相邻两项差为 \(0\) 的准良好数列是良好数列。
现在假入我们有一个最大值为 \(i\) 准良好数列,我们要加入一些新数 \(i+1\),那么这些新数必定只能插在相邻两项差为 \(0\) 的空隙(下称为 \(0\) 空隙)中,同时使原先的所有 \(0\) 空隙消失。
我们设原先有 \(i\) 个 \(0\) 空隙,新加入 \(j\) 个数(当然,\(j\) 必须大于等于 \(i\))。那么相当于我们一共有 \(i\) 个桶,在保证每个桶里都至少有一个球的情况下将 \(j\) 个球放入桶中,显然会产生 \(j-i\) 个新 \(0\) 空隙,而可能的放置情况用插板法求得有 \(\binom{j-1}{i-1}\)。所以我们再来一维 \(c\) 表示目前有 \(c\) 个 \(0\) 空隙。
那么我们就有了最终的 \(dp\) 状态 \(f_{i,j,c,l}\),表示枚举到第 \(i\) 个数,加入了 \(j\) 个数,能产生 \(l\) 个满足恰有 \(c\) 个 \(0\) 空隙的准良好序列。那么转移方程即为:
看似 \(O(n^5)\),实则由于最后一维跑不满,所以常数小的可怕。
统计答案考虑因为 \(i\) 枚举的是第几种数,至于第一种数是 \(1\) 是 \(2\) 并没有说明,所以:
#include<bits/stdc++.h>
using namespace std;
const int N=105,p=1e9+7;
int n,m,k,C[N][N],f[2][N][N][N],ans;
int main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>m>>k,C[0][0]=1;for(int i=1;i<=n;i++) f[1][i][i][1]=1;for(int i=0;i<=n;C[++i][0]=1)for(int j=1;j<=i;j++) C[i][j]=min(C[i-1][j]+C[i-1][j-1],101);for(int num=1,e=1;num<m;num++,e^=1){for(int i=num;i<=n;i++){for(int j=1;j<=i-num+2;j++) for(int c=1;c<=k;c++) if(f[e][i][j][c])for(int x=j,cc;x+i<=n;x++) if((cc=c*C[x-1][j-1])<=k&&cc)f[e^1][i+x][x-j][cc]=(f[e^1][i+x][x-j][cc]+f[e][i][j][c])%p;for(int j=1;j<=k;j++) ans=(ans+1ll*(m-num+1)*f[e][i][0][j])%p;}memset(f[e],0,sizeof(f[e]));}for(int i=m;i<=n;i++) for(int j=1;j<=k;j++) ans=(ans+f[m&1][i][0][j])%p;return cout<<ans,0;
}