转化一下题意,求有n个节点的小根堆一共有几种。
那么,显然递推了。
f[x]=C(x-1,left)*f[x-1-left]*f[left]
left表示一个儿子的大小。
显然,记忆化好写很多。
要用Lucas
#include<bits/stdc++.h>
#define LL long long
#define MAXN 1000000
using namespace std;
LL fac[MAXN+1],n,p;
LL dp[MAXN+1];
LL ksm(LL A,LL B,LL C)
{
LL Ans=1;
while(B)
{
if(B&1)Ans=Ans*A%C;
A=A*A%C;
B>>=1;
}
return Ans;
}
LL C(LL N,LL M,LL P)
{
return fac[N]*ksm(fac[M],P-2,P)%P*ksm(fac[N-M],P-2,P)%P;
}
LL Lucas(LL N,LL M,LL P)
{
if(N==0||M==0)return 1;
return Lucas(N/P,M/P,P)*C(N%P,M%P,P)%P;
}
LL f(LL x)
{
if(dp[x])return dp[x];
if(x==0)return dp[x]=1;
if(x==1)return dp[x]=1;
LL dep=log2(x);
LL tot=((LL)1<<dep)-1;
LL left=(tot-1)/2+min(x-tot,(tot+1)/2);
return dp[x]=Lucas(x-1,left,p)*f(x-1-left)%p*f(left)%p;
}
int main()
{
cin>>n>>p;
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%p;
cout<<f(n);
return 0;
}