D Madoka and The Corruption Scheme
D Madoka and The Corruption Scheme
题意
给定一场比赛,有 \(2^n\) 个参赛者,参赛者按照一定顺序排列,一共 \(n\) 轮比赛,其中每场相邻两个比赛,获胜者进入下一轮,所有获胜者的相对排列顺序不变。比赛赞助方可以耍流氓随意改变至多 \(k\) 次比赛的结果。求获胜者的最大值的最小情况
题解
我们可以将其定义为一颗满二叉树,其中的每一条边可以被认为是一个参赛者在该轮比赛中获胜或者失败。从某个叶节点到根节点中间的 \(n\) 条边中如果至多有 \(k\) 个边是失败的,那么就可以通过修改比赛结果使他获胜。所以问题就转换成了统计从叶节点到根节点失败边个数 \(\geq k + 1\) 的节点个数。令失败边的个数为 \(x\) 。只需要使用组合数即可,也就是求出从 \(n\) 个边中选择 \(x\) 个边作为失败边即可,然后保证这 \(\tbinom{n}{x}\) 个参赛者的序号最大即可。
code
const ll mod = 1e9 + 7, N = 2e5 + 10;
ll n, k;
ll fac[N], inv[N];
ll qpow(ll a, ll b) {
ll res = 1ll;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void sieve() {
fac[0] = fac[1] = 1;
for (int i = 2; i < N; i++) fac[i] = fac[i - 1] * i % mod;
inv[N - 1] = qpow(fac[N - 1], mod - 2);
for (int i = N -2 ; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
inline ll C(ll n, ll m) {
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void slove() {
cin >> n >> k;
sieve();
ll ans = qpow(2, n);
if (k < n) {
for (int i = k + 1; i <= n; i++) {
ll t = C(n, i);
ans = ((ans - t) % mod + mod) % mod;
}
}
cout << ans << '\n';
}