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;
}
上一篇:Atcoder TypicalDPContest N~T


下一篇:loj #6216. 雪花挂饰