如果能够根据题意看出这是一个堆的话,那么就有些思路了。。
首先堆顶必须是最小元素,然后左右儿子可以预处理出来都有多少个数,
把剩余的数任意分配给两个儿子,用排列组合即可
dp(now) = dp(now << 1) * dp(now << 1 | 1) * C(sum[now] - 1, sum[now << 1])
#include <cstdio>
#define N 5000001
#define LL long long
int n;
LL p, inv[N], A[N], B[N], s[N];
inline LL C(int x, int y)
{
return A[x] * B[y] % p * B[x - y] % p;
}
inline LL dp(int now)
{
if(!s[now] || s[now] == 1) return 1;
return dp(now << 1) * dp(now << 1 | 1) % p * C(s[now] - 1, s[now << 1]) % p;
}
int main()
{
int i, j;
scanf("%d %lld", &n, &p);
inv[1] = A[1] = A[0] = B[0] = B[1] = 1;
for(i = 2; i <= n; i++)
{
inv[i] = -(p / i) * inv[p % i] % p;
A[i] = A[i - 1] * i % p;
B[i] = B[i - 1] * inv[i] % p;
}
for(i = 1; i <= n; i++)
for(j = i; j; j >>= 1) s[j]++;
printf("%lld
", (dp(1) + p) % p);
return 0;
}