loading

ARC093F Dark Horse

题意

\(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+\{k\}}\leftarrow -f_{i+1,j}\cdot \dbinom{2^n-a_i-j}{2^k-1}\cdot (2^k)! \]

不钦定则有 \(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);
}
posted @ 2025-02-05 22:45  dcytrl  阅读(18)  评论(0)    收藏  举报