大致题意就是数有多少棵 $n$ 个点的二叉树,编号为 $1\sim n$ 的排列,要求有一个叶子编号为 $R$,并且二叉树满足大根堆的性质(父亲大于所有子节点)。对 $m$ 取模。$1\le n, R \le 2021$。

首先可以转化为小根堆,此时要求的叶子节点就是 $L=n-R+1$。设 $t(n)$ 表示在不考虑叶子限制的情况下 $n$ 个点的满足小根堆性质的二叉树数目,那么可以枚举左右儿子的点的个数即可,就有
$$
t(i) = \sum\limits_{j=1}^{(i-1)/2}t(j)t(i-1-j)\binom{i-1}{j}
$$
然后注意一下本题左右子树是可交换的,那么就要在两棵子树大小相等时除以 2。而这题恶心的地方在于 $m$ 不一定是质数,那么首先就保存模 $2m$ 的组合数,除以 2 时直接除即可。

接下来考虑带有叶子的限制。考虑 $t(n)$ 的另一种推法,即此时 $L$ 不一定是叶子节点。那么可以枚举 $L$ 下面有多少节点(即多少节点比 $L$ 大),设有 $k$ 个,然后这些点带上 $L$ 的贡献就是 $t(k+1)$。然后还剩下 $n-k$ 个点以 $L$ 为叶子,那么就有:
$$
t(i) = \sum\limits_{k=0}^{i-L}\binom{i-L}{k} t(k+1) ans(i-k)
$$
反解出 $ans(i) = t(i) - \sum\limits_{k=1}^{i-L}\binom{i-L}{k} t(k+1) ans(i-k)$
最后答案就是 $ans(n)$。

总之这个题很奇妙......貌似还有更简单的推法(不会,我爬了)

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 2050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used:
    system("pause");
#endif
}
int n, r, m;
ll C[N][N], C2[N][N];
ll t[N], ans[N];
void preC()
{
    C[0][0] = 1;
    for (int i = 1; i < N; ++i)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; ++j)
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1])
    }
    C2[0][0] = 1;
    for (int i = 1; i < N; ++i)
    {
        C2[i][0] = 1;
        for (int j = 1; j <= i; ++j)
            C2[i][j] = (C2[i - 1][j] + C2[i - 1][j - 1])
    }
}

inline void solve()
{
    scanf(
    preC();
    r = n - r + 1;
    t[0] = t[1] = 1;
    for (int i = 2; i <= n; ++i)
        for (int j = 0; j <= ((i - 1) >> 1); ++j)
        {
            ll x = ((i & 1) && j == ((i - 1) >> 1)) ? C2[i - 1][j] / 2 : C[i - 1][j];
            x = x * t[j]
            t[i] = (t[i] + x)
        }
    for (int nn = r; nn <= n; ++nn)
    {
        ll res = 0;
        for (int k = 1; k <= nn - r; ++k)
        {
            ll zu = C[nn - r][k] * ans[nn - k]
            res = (res + zu)
        }
        res = (t[nn] - res + m)
        ans[nn] = res;
    }
    printf(
}

int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf(
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}