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) 这些位置上的最小值。写成通项:
那么我们要求 (forall kin [1,n],min P_k otin A)。
“最小值不属于 (A)”的方案太多,但是“最小值属于 (A)”却给了一个最小值是某个 (a_i) 的限制。所以这个反面更可做。
考虑容斥。
其中 (F(S)) 表示 (S) 中的 (P) 均满足 (min Pin A),而非 (S) 中的 (P) 无所谓的方案数。非 (S) 中的 (P) 的方案数可以在 (S) 中的 (P) 确定后用排列数搞定,所以进一步的,
其中 (G(S)) 表示给 (S) 中的 (P) 分配选手使得他们满足条件的方案数。
显然若 (a_i<a_j),那么最小值钦定为 (a_j) 的 (P) 能够选的其他球包含于最小值钦定为 (a_i) 的 (P) 能选的球。按 (A) 中元素从大到小DP,记 (G(i,S)) 表示做到 (a_i) 被钦定的集合是 (S) 时的方案数,对于每一个 (a_i),我们做如下两个决策之一:
-
不把 (a_i) 作为某一集合钦定的最小值。
-
钦定 (a) 作为 (P_k) 的最小值,并再选取大于 (a) 且未被选取的 (2^{k-1}-1) 个数。
最终答案为
时间复杂度 (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
",ans);
return 0;
}