题意
有 \(2^n\) 个人按照满二叉树的形态进行淘汰赛,你是 \(1\) 号,有 \(m\) 个人能打赢你,其他人都打不过你。对于其他人,编号小的人胜利。你现在要把这些人放在满二叉树的叶子上并打淘汰赛,显然一共 \((2^n)!\) 种方案。问最终胜利的人是你的方案数。
\(n,m\le 16\)。
分析
题目要求你 \(n\) 场比赛必须全赢,这比较难处理,考虑容斥,钦定若干场比赛你会输掉。当然,这种情况下即使你输了仍然会晋级。为了方便,不妨让你自己待在 \(1\) 号位置。如果某个人 \(i\) 要在第 \(j\) 轮比赛中胜出,那么你就需要在编号大于 \(i\) 的 \(n-i\) 个数中选出 \(2^j-1\) 个炮灰。而编号越大,限制越紧,于是考虑从后往前 dp,设 \(f_{i,j}\) 表示 \([i,m]\) 中的人已经钦定 \(j\) 个人参加比赛的方案数,同时 \(j\) 也代表了已经钦定过的比赛编号集合,带容斥系数。转移则考虑当前是否钦定 \(i\) 胜利,若钦定则需要选出一场没钦定过的比赛 \(k\),然后在 \(2^n-a_i-j\) 个炮灰中选择 \(2^k-1\) 个,然后让炮灰们在 \(2^k\) 内部自由排序,然后乘上 \(-1\) 的容斥系数:
不钦定则有 \(f_{i,j}\leftarrow f_{i+1,j}\)。
计算答案时没被钦定的那些人在剩下的位置自由排序即可,有 \(ans\leftarrow f_{1,j}\cdot(2^n-1-j)!\)。
最后,由于 \(1\) 可以在任何位置,而实际上 \(1\) 在哪个位置方案数都是一样的,于是答案自乘 \(2^n\) 即可,复杂度 \(O(2^nnm)\)。
int n,m,a[maxn];
int f[maxn][maxm];
int fac[maxm],inv[maxm];
int ksm(int x,int y){int res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;
}
int C(int x,int y){if(x<y)return 0;return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
inline void adder(int &x,int y){x+=y,x=x>=mod?x-mod:x;}
inline void suber(int &x,int y){x-=y,x=x<0?x+mod:x;}
void init(int lim){fac[0]=1;rep(i,1,lim)fac[i]=fac[i-1]*i%mod;inv[lim]=ksm(fac[lim],mod-2);per(i,lim-1,0)inv[i]=inv[i+1]*(i+1)%mod;
}
inline void solve_the_problem(){n=rd(),m=rd(),init(1<<n);rep(i,1,m)a[i]=rd();f[m+1][0]=1;per(i,m,1)rep(S,0,(1<<n)-1)if(f[i+1][S]){adder(f[i][S],f[i+1][S]);rep(j,0,n-1)if(!((S>>j)&1)){suber(f[i][S|(1<<j)],f[i+1][S]*C((1<<n)-a[i]-S,(1<<j)-1)%mod*fac[1<<j]%mod);}}int ans=0;
// write(f[1][1],32),write(f[1][2]);rep(S,0,(1<<n)-1)adder(ans,f[1][S]*fac[(1<<n)-1-S]%mod);write((1ll<<n)*ans%mod);
}