Codeforces Round #818 (Div. 2) - D. Madoka and The Corruption Scheme

思维+组合数学

Problem - D - Codeforces

题意

2n 个人进行锦标赛,编号1~2n,每一场输的人失去比赛资格,赢的人继续。Madoka可以选择他们进行的顺序,以及决定哪一边赢得比赛。你的目标是尽量让编号小的赢得最终比赛。 主办方可以改变其中至多k场比赛的结果,即本来是左边赢的改为右边赢,本来是右边赢的改为左边。如下图所示,左边红线是你选择的胜方。而主办方改动左边的一个结果,使得最终赢的人变成3。

img

问题是,求最小的编号,使得存在一个最优方案,使得无论主办方怎么改,都可以让他赢。主办方目标是让赢的人编号更大。

思路

  1. 转换为图论问题:设 Madoka 一开始规定的红边权值是 0,黑边权值是 1,记 f[x] 为从根节点到编号 x 的结点的路径边权和
  2. 若主办方想让编号为 x 的成为冠军,则 f[x]<=k (主办方必须把这 f[x] 条边全部逆转)
  3. 因为有 2n 个叶子,就有 2n 种互不相同的路径,权值为 i 的叶子相当于长度为 n 的路径上选 i 个黑边,有 (ni) 个,所以主办方只能把 i=0k(ni) 个叶子放到冠军,因此 Madoka 贪心地把编号最小的放到这些叶子的位置即可

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e5 + 10, mod = 1e9 + 7;
int n, k;
ll fac[N], finv[N];
ll qmi(ll a, ll b)
{
	ll ans = 1;
	while(b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans;
}

void presolve(int n)
{
	fac[0] = finv[0] = 1;
	for (int i = 1; i <= n; i++)
		fac[i] = fac[i-1] * i % mod;
	finv[n] = qmi(fac[n], mod - 2);
	for (int i = n - 1; i >= 1; i--)
		finv[i] = finv[i+1] * (i + 1) % mod;
}

ll C(int n, int m)
{
	if (m < 0 || n - m < 0)
		return 0;
	return fac[n] * finv[m] % mod * finv[n-m] % mod;
}
ll solve()
{
	if (k >= n)
		return qmi(2, n);
	ll ans = 0;
	for (int i = 0; i <= k; i++)
		ans = (ans + C(n, i)) % mod;
	return ans;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> k;
	presolve(n);
	cout << solve() << endl;
    return 0;
}
posted @   hzy0227  阅读(53)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示