ARC93F Dark Horse

Dark Horse

\(2^n\) 个人打锦标赛,他们的过程是随机一个排列,然后按照这个排列站好。每轮是第 \(2i − 1\) 个人和第 \(2i\) 的人比赛,败者淘汰。

你是 \(1\) 号选手,你碰到 \(a_1, a_2,\dots, a_m\) 会输,碰到剩下的会赢。如果比赛和你无关,那么编号小的赢。

求有多少个排列,能够使你最后赢。答案对 \(10^9 + 7\) 取模。

\(1 ≤ n ≤ 16, 0 ≤ m ≤ 16, 2 ≤ a_i ≤ 2^n\)

题解

对做题的人而言,分析法比解析法更有逻辑。

首先可以发现这棵二叉树每个非叶子节点都可以交换左右儿子。所以我们可以钦定 \(1\) 号选手站在 \(1\) 号位置来找本质不同的方案。

既然要 \(1\) 号胜出,那么我们就来看看 \(1\) 号最终会跟哪些人比赛。显然有 \(\{2\},\{3,4\},\{5,6,7,8\}\dots\) 这些位置上的最小值。写成通项:

\[P_k=\{p_{2^{k-1}+1},\dots,p_{2^k}\},k\in[1,n] \]

那么我们要求 \(\forall k\in [1,n],\min P_k\notin A\)

“最小值不属于 \(A\)”的方案太多,但是“最小值属于 \(A\)”却给了一个最小值是某个 \(a_i\) 的限制。所以这个反面更可做。

考虑容斥。

\[\frac{ans}{2^n}=(2^n-1)!+\sum_{S\subseteq \{P\}}(-1)^{|S|}F(S) \]

其中 \(F(S)\) 表示 \(S\) 中的 \(P\) 均满足 \(\min P\in A\),而非 \(S\) 中的 \(P\) 无所谓的方案数。非 \(S\) 中的 \(P\) 的方案数可以在 \(S\) 中的 \(P\) 确定后用排列数搞定,所以进一步的,

\[F(S)=(2^n-1-\sum_{P\in S}|P|)!G(S) \]

其中 \(G(S)\) 表示给 \(S\) 中的 \(P\) 分配选手使得他们满足条件的方案数。

显然若 \(a_i<a_j\),那么最小值钦定为 \(a_j\)\(P\) 能够选的其他球包含于最小值钦定为 \(a_i\)\(P\) 能选的球。按 \(A\) 中元素从大到小DP,记 \(G(i,S)\) 表示做到 \(a_i\) 被钦定的集合是 \(S\) 时的方案数,对于每一个 \(a_i\),我们做如下两个决策之一:

  1. 不把 \(a_i\) 作为某一集合钦定的最小值。

  2. 钦定 \(a\) 作为 \(P_k\) 的最小值,并再选取大于 \(a\) 且未被选取的 \(2^{k-1}-1\) 个数。

最终答案为

\[ans=2^n\left((2^n-1)!+\sum_{S\subseteq \{P\}} (-1)^{|S|}\times (2^n-\sum_{P\in S}|P|)!\times G(1,S)\right) \]

时间复杂度 \(O(2^nnm)\)

CO int N=20,S=65536+10;
int a[N];
int fac[S],ifac[S],dp[N][S];

IN int binom(int n,int m){
	return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main(){
	int n=read<int>(),m=read<int>();
	for(int i=m;i>=1;--i) read(a[i]);
	int all=1<<n;
	fac[0]=1;
	for(int i=1;i<=all;++i) fac[i]=mul(fac[i-1],i);
	ifac[all]=fpow(fac[all],mod-2);
	for(int i=all-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
	dp[0][0]=1;
	for(int i=1;i<=m;++i)for(int s=0;s<all;++s){
		int left=all-a[i]+1-s;
		cadd(dp[i][s],dp[i-1][s]);
		for(int j=0;j<n;++j)if(~s>>j&1){
			if(left<1<<j) break;
			cadd(dp[i][s|1<<j],mul(dp[i-1][s],
				 mul(binom(left-1,(1<<j)-1),fac[1<<j])));
		}
	}
	int ans=fac[all-1];
	for(int s=1;s<all;++s){
		int sum=mul(dp[m][s],fac[all-1-s]);
		cadd(ans,__builtin_popcount(s)&1?mod-sum:sum);
	}
	cmul(ans,all);
	printf("%d\n",ans);
	return 0;
}

posted on 2020-01-04 15:57  autoint  阅读(129)  评论(0编辑  收藏  举报

导航