这显然是一个二叉堆,然而我一开始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;
}
View Code