【CCPC】The 2024 Shanghai Collegiate Programming Contest F

news2024/10/6 2:30:56

羁绊大师

#动态规划 #图论 #并查集 #背包

题目描述

在某一自走棋游戏中,胖胖龙此刻拥有 n n n 个英雄,其中第 i i i 个英雄拥有两种羁绊,分别为 a i , b i ( a i < b i ) a_i, b_i(a_i < b_i) ai,bi(ai<bi)
不存在两个英雄拥完全相同的两种羁绊,即对于 1 ≤ i < j ≤ n 1 ≤ i < j ≤ n 1i<jn, 有 a i ≠ a j a_i\neq a_j ai=aj b i ≠ b j b_i \neq b_j bi=bj 。因为该游戏模式
的特殊性,一共具有 m 种羁绊,且每种羁绊至至至多多多只有两个英雄拥有。当胖胖龙处于等级 L L L 时,可以选
择自己的 L L L 个英雄上阵。对于每种羁绊,当且仅当上阵英雄中有两个英雄拥有此羁绊时,此羁绊为激活
状态。
胖胖龙的梦想是成为羁绊大师,他希望选出 L L L 个英雄上阵,使得自己激活的羁绊种数尽可能多。胖胖龙
希望你能帮帮他,如果你帮助了他,他会给你跳一段节奏鲜明而富有动感的舞蹈。
请你分别对 L ∈ { 1 , 2 ⋅ ⋅ ⋅ n } L ∈ \{1, 2 · · · n\} L{1,2⋅⋅⋅n} n n n种情况,分别输出激活羁绊的最大数量。

输入格式

第一行,包含两个非负整数 n, m(1 ≤ n ≤ 105, n ≤ m ≤ 2n) 分别表示胖胖龙此时拥有的英雄数量,以及
游戏中存在羁绊的数量。
接下来 n 行,第 i 行包含两个整数 ai, bi(1 ≤ ai < bi ≤ m) 分别表示第 i 个英雄拥有的两种羁绊。

输出格式

输出一行,包含 n 个整数,从左到右第 i 个整数表示当 L = i 时,胖胖龙最多能够激活的羁绊种数。整
数之间用一个用空格隔开。

样例 #1

样例输入 #1

10 10
1 2
2 3
1 3
4 5
5 6
6 7
4 7
8 9
9 10
8 10

样例输出 #1

0 1 3 4 4 6 7 7 8 10

解法

解题思路

对于一个英雄有两个羁绊,一个羁绊最多有两个英雄拥有。如果我们把羁绊看做一个点,英雄看做一条边,那么整张图只有环和链,不存在环中带链,因为每个点最多就两个度数。

那么,题目要求我们选择最多的羁绊,而这个羁绊必须被两个英雄共有才生效,转换在图中就是,环对应的贡献就是环的大小,链对应的贡献就是链的大小 − 1 -1 1,因此我们要尽可能选多的环。

而对于环和链的维护,一种是建图后染色,一种是使用并查集,这里使用并查集来维护。

那么,我们可以把环看做物品, L L L看做背包容量,然后去跑背包。如果背包容量大于全部环
的大小,那么我们只需要判断能取多少个链即可,需要贪心地从大到小来取,因为要尽可能少的取。

而对于背包容量小于环的,如果跑完背包后刚好装满,那么贡献就是背包容量,否则就是背包容量 − 1 -1 1,因为我们可以把剩下的环拆成链,这样只有一条链,负面贡献为 1 1 1

由于这个物品实际上是会重复的,并且至多只会有 m \sqrt m m 种,如果单纯跑 01 01 01背包复杂度将会在 O ( n m ) O(nm) O(nm)

因此我们,需要统计种类,然后使用二进制优化,或者单调队列优化来优化这个多重背包,使用单调队列优化复杂度在 O ( m ∗ n ) O(\sqrt m *n) O(m n)。当然二进制优化也能过 ,并且这题种类不会很多,使用二进制优化跑的更快。

代码(二进制优化)

//solve函数
const int N = 2e5 + 10;
 
int fa[N], siz[N];
inline int find(int x) {
	return fa[x] = fa[x] == x ? x : find(fa[x]);
}
 
void solve() {
	int n, m;
	std::cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		siz[i] = 1;
		fa[i] = i;
	}
 
	std::vector<bool> cyc(m);
	for (int i = 1; i <= n; i++) {
		int u, v;
		std::cin >> u >> v;
		int a = find(u), b = find(v);
		if (a == b) {
			cyc[a] = true;
		}
		else {
			fa[b] = a;
			siz[a] += siz[b];
		}
	}
 
	int sum = 0;
	std::map<pii, int>mp;
	std::vector<int>b;
	for (int i = 1; i <= m; ++i) {
		if (fa[i] == i) {
			if (cyc[i]) {
				mp[{siz[i], siz[i]}]++;
				sum += siz[i];
			}
			else {
				b.push_back(siz[i] - 1);
			}
		}
	}
 
	std::vector<int>f(n + 1);
 
	std::vector<int>aa, bb;
	for (auto& [t, z] : mp) {
		auto [y, x] = t;
 
		for (int k = 0; k < 32; ++k) {
			if (z - (1LL << k) <= 0) break;
 
			aa.push_back((1LL << k) * y);
			bb.push_back((1LL << k) * x);
 
			z -= 1LL << k;
		}
		if (z) {
			aa.push_back(z * y);
			bb.push_back(z * x);
		}
	}
 
	for (int i = 0; i < bb.size(); ++i) {
		for (int j = n; j >= aa[i]; --j) {
			f[j] = std::max(f[j], f[j - aa[i]] + bb[i]);
		}
	}
 
	std::sort(b.begin(), b.end(), std::greater<>());
 
	int j = 0;
	std::vector<int>res(n + 1);
	int s = sum;
	for (int i = 1; i <= n; ++i) {
		if (i <= s) {
			res[i] = i - !(f[i] == i);
		}
		else {
			while (i > sum) sum += b[j++];
			res[i] = i - j;
		}
	}
 
	for (int i = 1; i <= n; ++i) {
		std::cout << res[i] << " ";
	}
	std::cout << "\n";
}
 
signed main() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);
 
	int t = 1;
	//std::cin >> t;
 
	while (t--) {
		solve();
	}
}

代码(单调队列优化)

const int N = 2e5 + 10;
 
int fa[N], siz[N];
int q[N];
inline int find(int x) {
	return fa[x] = fa[x] == x ? x : find(fa[x]);
}
 
void solve() {
	int n, m;
	std::cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		siz[i] = 1;
		fa[i] = i;
	}
	
	std::vector<bool> cyc(m);
	for (int i = 1; i <= n; i++){
		int u, v;
		std::cin >> u >> v;
		int a = find(u), b = find(v);
		if (a == b) {
			cyc[a] = true;
		}
		else {
			fa[b] = a;
			siz[a] += siz[b];
		}
	}
 
	int sum = 0;
	std::map<pii, int>mp;
	std::vector<int>b;
	for (int i = 1; i <= m ; ++i) {
		if (fa[i] == i) {
			if (cyc[i]) {
				mp[{siz[i], siz[i]}]++;
				sum += siz[i];
			}
			else {
				b.push_back(siz[i] - 1);
			}
		}
	}
 
	std::vector<int>f(n + 1);
	for (auto& [x, s] : mp) {
		auto g = f;
		auto [v, w] = x;
 
		for (int j = 0; j < v; ++j) {
			int h = 0, t = -1;
			for (int k = j; k <= n; k += v) {
				while (h <= t && q[h] < k - s * v) {
					h++;
				}
				if (h <= t) {
					f[k] = std::max(g[k], g[q[h]] + (k - q[h]) / v * w);
				}
				while (h <= t && g[k] >= g[q[t]] + (k - q[t]) / v * w) {
					t--;
				}
				q[++t] = k;
			}
		}
	}
 
	std::sort(b.begin(), b.end(), std::greater<>());
 
	int j = 0;
	std::vector<int>res(n + 1);
	int s = sum;
	for (int i = 1; i <= n; ++i) {
		if (i <= s) {
			res[i] = i - !(f[i]==i);
		}
		else {
			while (i > sum) sum += b[j++];
			res[i] = i - j;
		}
	}
 
	for (int i = 1; i <= n; ++i) {
		std::cout << res[i] << " ";
	}
	std::cout << "\n";
}
 
signed main() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);
 
	int t = 1;
	//std::cin >> t;
 
	while (t--) {
		solve();
	}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190967.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AIGC】ChatGPT提示词Prompt助力自媒体内容创作升级

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;高效仿写专家级文章提示词使用方法 &#x1f4af;CSDN博主账号分析提示词使用方法 &#x1f4af;自媒体爆款文案优化助手提示词使用方法 &#x1f4af;小结 &#x1f4af…

王者农药更新版

一、启动文件配置 二、GPIO使用 2.1基本步骤 1.配置GPIO&#xff0c;所以RCC开启APB2时钟 2.GPIO初始化&#xff08;结构体&#xff09; 3.给GPIO引脚设置高/低电平&#xff08;WriteBit&#xff09; 2.2Led循环点亮&#xff08;GPIO输出&#xff09; 1.RCC开启APB2时钟。…

Transformer架构概述(二)

目录 1. Transformer架构概述 1.1 《Attention is All You Need》论文概述 1.2 Transformer的模块组成 1.3 Encoder 和 Decoder 的区别与联系 2. Transformer的并行计算效率相对于RNN的提升 2.1 RNN中的顺序处理问题 2.2 Transformer中的并行化优势 3. Self-Attention机…

Spring Boot框架下的大学生就业招聘平台

5系统详细实现 5.1 用户模块的实现 5.1.1 求职信息管理 大学生就业招聘系统的用户可以管理自己的求职信息&#xff0c;可以对自己的求职信息添加修改删除操作。具体界面的展示如图5.1所示。 图5.1 求职信息管理界面 5.1.2 首页 用户登录可以在首页看到招聘信息展示也一些求职…

setTimeout,setInterval ,requestAnimationFrame定时器

setTimeout&#xff0c;setInterval &#xff0c;requestAnimationFrame定时器 定时器函数通常用于执行定时任务&#xff0c;也就是说你做了一个功能放在定时器函数里&#xff0c;它可以在特定的时间去执行你的指令&#xff0c;或者说隔多长时间&#xff08;单位时间内—毫秒为…

为什么每个人都要学习项目管理?

在这个已然到来的超级个体时代&#xff0c;项目管理这项技能&#xff0c;不仅仅是项目经理才需要掌握的&#xff0c;而是每个想要独当一面之人的必备技能。 所谓的独当一面&#xff0c;就是从一个人做好自己的事&#xff0c;到带领一群人从头到尾把事做成。而学习项目管理&…

路由器的工作机制

在一个家庭或者一个公司中 路由器的作用主要有两个(①路由–决定了数据包从来源到目的地的路径 通过映射表决定 ②转送–通过路由器知道了映射表 就可以将数据包从路由器的输入端转移给合适的输出端) 我们可以画一张图来分析一下&#xff1a; 我们好好来解析一下这张图&#x…

Chromium 搜索引擎功能浅析c++

地址栏输入&#xff1a;chrome://settings/searchEngines 可以看到 有百度等数据源&#xff0c;那么如何调整其顺序呢&#xff0c;此数据又存储在哪里呢&#xff1f; 1、浏览器初始化搜索引擎数据来源在 components\search_engines\prepopulated_engines.json // Copyright …

el-pagination组件封装

组件使用 源代码&#xff1a; <script setup> import Pagination from /components/pagination/index.vue import {ref} from "vue";const pageNum ref(1) const pageSize ref(10) const total ref(120)function loadData() {// 加载数据 } </script>…

C++教程一口气讲完!(万字讲解)( ̄y▽ ̄)╭ Ohohoho... 下

C 常量 常量是固定值&#xff0c;在程序执行期间不会改变。这些固定的值&#xff0c;又叫做字面量。 常量可以是任何的基本数据类型&#xff0c;可分为整型数字、浮点数字、字符、字符串和布尔值。 常量就像是常规的变量&#xff0c;只不过常量的值在定义后不能进行修改。 …

【设计模式】软件设计原则——开闭原则里氏替换单一职责

开闭原则内容引出 开闭原则 定义&#xff1a;一个软件实体&#xff0c;类&#xff0c;函数&#xff0c;模块&#xff1b;对扩展开放&#xff0c;对修改关闭。用抽象构建框架&#xff0c;用实现扩展细节。可以提高软件的可复用性和可维护性。 开发新功能时&#xff0c;尽量不修…

Redis实现每日签到(大数据量)

PHP语言使用Redis NoSQL服务器二进制数据类型实现大数据情况下签到功能 目录 问题 解决方式 封装签到类 功能调用 总结 问题 实现用户每日签到功能不难&#xff0c;但随着用户量上升之后&#xff0c;不论是存储还是判断对数据量来说都很麻烦&#xff1b;假如每天有100万用…

pytorch 与 pytorch lightning, pytorch geometric 各个版本之间的关系

主要参考 官方的给出的意见&#xff1b; 1. pytorch 与 pytorch lightning 各个版本之间的关系 lightning 主要可以 适配多个版本的 torch; https://lightning.ai/docs/pytorch/latest/versioning.html#compatibility-matrix&#xff1b; 2. pytorch 与 pytorch geometric 各…

深度学习-----------------------------束搜索

目录 贪心搜索&#xff08;一般来说计算最快的&#xff09;穷举搜索&#xff08;一般来说是最好的&#xff0c;但可能算不动&#xff09;束搜索&#xff08;Beam Search&#xff09; 总结 贪心搜索&#xff08;一般来说计算最快的&#xff09; 在seq2seq中使用贪心搜索来预测序…

软考数据库部分 ---- (概念数据库模型,三级模式,两级映像,事物管理)

文章目录 一、概念数据库模型二、结构数据库模型三、三级模式四、两级映像五、关系模式基本术语六、关系模式七、关系的数学定义八、数据定义语言九、SQL访问控制十、视图十一、索引十二、关系模式十三、范式十四、数据库设计十五、事物管理&#xff08;ACID&#xff09;十六、…

基于SPI协议的Flash扇区擦除实验

当一块Flash芯片中的不同的扇区烧录了不同的程序&#xff0c;而我们只想擦除某个扇区的程序保留其他程序时&#xff0c;Flash的全擦除是不能满足要求的&#xff0c;这时候就需要扇区擦除来实现这一功能。扇区擦除可以对Flash芯片中的某一扇区进行擦除而不改变其他扇区中的存储数…

2.3MyBatis——插件机制

2.3MyBatis——插件机制 1.基本用法2.原理探究2.1加载过程2.2执行过程2.2.1 插件的执行点2.2.2 SQL执行的几个阶段2.2.3 如何梳理出执行流程 插件机制是一款优秀框架不可或缺的组成部分&#xff0c;比如spring、dubbo&#xff0c;还有我们要聊的Mybatis等等。所谓插件&#xff…

【AI大模型】使用Embedding API

一、使用OpenAI API 目前GPT embedding mode有三种&#xff0c;性能如下所示&#xff1a; 模型每美元页数MTEB得分MIRACL得分text-embedding-3-large9,61554.964.6text-embedding-3-small62,50062.344.0text-embedding-ada-00212,50061.031.4 MTEB得分为embedding model分类…

Linux驱动开发(速记版)--printctl子系统

第102章 pinctrl 子系统的引入 Linux中的 pinctrl子系统是管理和配置GPIO引脚的框架&#xff0c;提供标准化方法以适应不同硬件。 它遵循 Linux内核设备模型&#xff0c;分为设备、驱动等部分。 本章节从设备和驱动角度介绍 pinctrl子系统。 102.1 pinctrl 设备树 在设备树中&a…

旅游心动盲盒:开启个性化旅行新体验

嘿&#xff0c;宝子们&#xff01;在如今这个数字化时代呀&#xff0c;文心智能体可是给咱们的生活带来了超多便利和创新呢。今天呀&#xff0c;我来给大家介绍一款超棒的智能体——旅游心动盲盒&#xff0c;它肯定能给你的旅行带来全新的惊喜和超个性化的体验哟。 一、项目背…