推公式+Lucas定理
F[i]表示以i为根节点的堆的方案数
F[i] = F[2*i] * F[i*2+1] * C( d[i]-1 , d[2*i])
当n>=p的时候需要lucas定理
#include <iostream>
#include <cstdio>
#define N 5000050
using namespace std;
typedef long long LL;
LL d[N],F[N],jc[N],k; int n;
LL qp(LL a,LL b) {
LL r = 1LL;
while (b) {
if (b&1) r = (r * a) % k;
b >>= 1; a = (a * a) % k;
}
return r;
}
LL C(LL a,LL b) {
if (b>a) return 0;
if (b>=k || a>=k) return C(a/k , b/k) * C(a%k , b%k) % k;
LL r = jc[a] * qp(jc[b],k-2) % k;
r = r * qp(jc[a-b],k-2) % k;
return r;
}
inline void solve() {
cin >> n >> k;
jc[0] = 1LL;
for (int i=1;i<=1000000;i++) jc[i] = jc[i-1] * i % k;
for (int i=n;i>=1;i--) d[i] = d[2*i] + d[2*i+1] + 1;
for (int i=n;i>=1;i--) {
LL debug = C(d[i]-1,d[2*i]);
F[i] = ( ( (2*i)<=n ? F[2*i] : 1 ) * ( (2*i+1)<=n ? F[2*i+1] : 1) % k ) * C(d[i]-1,d[2*i]) % k;
}
cout << F[1] << endl;
}
int main()
{
solve();
return 0;
}