ARC093F Dark Horse 题解
题意
- 有 个人,编号为 ,他们要进行一场比赛。
- 他们首先会排成一排形成一个排列,然后每一轮第 和第 个人对抗,留下胜利者,最终留下的人是冠军。
- 另有一个大小为 的编号集合 ,编号为 的对抗结果如下:
- 若 且 ,则 胜。
- 否则 胜。
- 求能使得编号为 的人成为冠军的排列数。
- ,,答案对 取模。
题解
要成为冠军必须打败 个对手,第 个对手来自大小为 的子树中,也就是 个数中的 。
于是问题变成求将 这 个数划分成 个集合,第 个集合中有 个数,每个集合中的 的方案数,然后乘上 。
考虑容斥,对于一个状态 ,若第 个集合的 ,则将 的第 位设为 。
最终答案为 ,其中 表示状态为 的方案数,可以通过对 中的数从大到小 DP 预处理出,总时间复杂度 。
代码
const int N = 16;
int n, m, a[N|1];
modint f[N|1][1<<N|1], ans;
int main() {
rd(n, m), rda(a, m);
reverse(a + 1, a + m + 1);
init(1 << n);
f[0][0] = 1;
for (int i = 1; i <= m; i++)
for (int j = 0; j < (1 << n); j++) {
f[i][j] += f[i-1][j];
for (int k = 0; k < n; k++)
if (!(j >> k & 1))
f[i][j|1<<k] += f[i-1][j] * binom((1 << n) - a[i] - j, (1 << k) - 1);
}
for (int i = 0; i < (1 << n); i++) {
int s = (1 << n) - 1 - i;
for (int j = 0; j < n; j++)
if (!(i >> j & 1)) f[m][i] *= binom(s, 1 << j), s -= 1 << j;
if (__builtin_popcount(i) & 1) ans -= f[m][i];
else ans += f[m][i];
}
ans *= 1 << n;
for (int i = 0; i < n; i++) ans *= p[1<<i];
print(ans);
return 0;
}
评论
暂无已公开评论。