题目
思路
因为不相交,所以每个点最多连出一条线,所以参与连线的点一定是偶数个
我们按照选出点的数量 2,4 …… 2x 将答案划分,答案可以表示为
(假设我们选出2x个点连线,假设方法数为
:2x个点参与连线的方案数)
如果我们确定一条线,还剩下
组,这条线肯定把剩下的
个点分成两个偶数点块(这样每个子块内才能继续完成连线)
于是问题就被划分为
![]()
——卡特兰数
2025.2.27更新 一个比较细节的做法,又快又不要求知道背景
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2024;
const int mod = 2023;
int c[N][N];
int f[N / 2 + 1];
void C(int n)
{
c[0][0] = 1; // 不用处理i=0,不用讨论i-1<0
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 - 1] + c[i - 1][j]) % mod;
}
}
int get(int n, int fa) // 记忆化
{
if (n < fa)
return f[n];
for (int i = 0; i < n; i++)
f[n] = (f[n] + get(i, fa) * get(n - 1 - i, fa) % mod) % mod;
return f[n];
}
int main()
{
C(2023);
f[0] = 1;
int ans = 1; //不连任何点对
for (int i = 2; i <= 2023; i += 2) // 必须是偶数个点才能组成点对
ans = (ans + c[2023][i] * get(i / 2, i / 2) % mod) % mod; // 选取i个点的方案数 * i/2个点对的连法的数目
printf("%d", ans);
}
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2023 + 10, mod = 2023;
int h[N] = {1, 1};
int c[N][N];
int main()
{
int n = 2023;
for(int i = 0; i <= n; i++)
c[i][0] = 1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= i; j++)
c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
for(int i = 2; i <= n; i++)
for(int j = 0; j < i; j++)
h[i] = (h[i] + h[j] * h[i-1-j]) % mod;
int ans = 1;
for(int i = 2; i <= n; i++)
if(i % 2 == 0)
ans = (ans + c[n][i] * h[i/2]) % mod;
cout << ans;
}