这显然是一个二叉堆,然而我一开始sha bi了,没想到树的形态是唯一的QwQ。因为是1到n的一个排列,所以数两两不同。用f[i]表示以二叉堆中编号为i的节点为根的子树的方案数,然后考虑如何求f,设lc,rc分别为i的左右子节点,则f[i]=f[lc]*f[rc]*C(size[i]-1,size[lc]),size就是子树大小。为什么*C(size[i]-1,size[lc])呢,这是左子树有哪些数的方案数,而i一定是最小的,所以i一定是根。组合数取模用Lucas就好了~
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #include<string> #include<ctime> #include<queue> #include<map> #include<set> #include<vector> typedef long long LL; using namespace std; const int N=2e6+10; LL n,p,f[N],fac[N],siz[N]; LL read() {LL d=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;} void judge(){freopen(".in","r",stdin); freopen(".out","w",stdout);} LL quickmi(LL a,LL b,LL p) { LL res=1; while (b) { if (b&1) res=res*a%p; a=a*a%p; b>>=1; } return res; } LL C(LL n,LL m,LL p) { if (n<m) return 0; if (n==m) return 1; return fac[n]*quickmi(fac[m]*fac[n-m]%p,p-2,p)%p; } LL lucas(LL n,LL m,LL p) { LL res=1; while (n&&m&&res) { res=res*C(n%p,m%p,p)%p; n/=p; m/=p; } return res; } int main() { //judge(); n=read(); p=read(); fac[1]=1; for (int i=2;i<=n;i++) fac[i]=fac[i-1]*i%p; for (int i=n;i>=1;i--) { int lc=i<<1,rc=lc|1; siz[i]=siz[lc]+siz[rc]+1; if (lc>n) f[lc]=1; if (rc>n) f[rc]=1; f[i]=f[lc]*f[rc]%p*lucas(siz[i]-1,siz[lc],p)%p; } printf("%lld",f[1]); return 0; }