【题目链接】
【思路要点】
- 记 dpi,j d p i , j 表示大小为 i i ,根节点距离为的左偏树的个数。
- 转移时枚举左右子树的大小,以及左子树根节点的距离即可。
- 时间复杂度 O(N2Log2N) O ( N 2 L o g 2 N ) ,可以用前缀和优化至 O(N2LogN) O ( N 2 L o g N ) 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
const int MAXLOG = 15;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int n, P, dp[MAXN][MAXLOG];
int main() {
read(n), read(P);
dp[0][0] = dp[1][1] = 1;
for (int i = 2; i <= n; i++)
for (int j = 1; (1 << j) - 1 <= i; j++) {
int tmp = 0;
for (int l = 0, r = i - 1; r >= 0; l++, r--)
for (int k = j - 1; (1 << k) - 1 <= l; k++)
tmp = (tmp + 1ll * dp[l][k] * dp[r][j - 1]) % P;
dp[i][j] = tmp;
}
int ans = 0;
for (int i = 1; (1 << i) - 1 <= n; i++)
ans = (ans + dp[n][i]) % P;
writeln(ans);
return 0;
}