版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/82049621
【题目链接】
【思路要点】
- 记 表示大小为 ,根节点距离为 的左偏树的个数。
- 转移时枚举左右子树的大小,以及左子树根节点的距离即可。
- 时间复杂度 ,可以用前缀和优化至 。
【代码】
#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;
}