如果能够根据题意看出这是一个堆的话,那么就有些思路了。。
首先堆顶必须是最小元素,然后左右儿子可以预处理出来都有多少个数,
把剩余的数任意分配给两个儿子,用排列组合即可
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; }