NC16430 [NOIP2016]蚯蚓
题目
题目描述
本题中,我们将用符号 表示对 c 向下取整,例如: 。
蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。
蛐蛐国里现在共有 n 只蚯蚓(n 为正整数)。每只蚯蚓拥有长度,我们设第 i 只蚯蚓的长度为 ,并保证所有的长度都是非负整数(即:可能存在长度为 0 的蚯蚓)。
每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数 p(是满足 0 < p < 1 的有理数)决定,设这只蚯蚓长度为 x,神刀手会将其切成两只长度分别为 和 的蚯蚓。特殊地,如果这两个数的其中一个等于 0,则这个长度为 0 的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加 q(是一个非负整常数)。
蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 m 秒才能到来 ……(m 为非负整数)
蛐蛐国王希望知道这 m 秒内的战况。具体来说,他希望知道:
·m 秒内,每一秒被切断的蚯蚓被切断前的长度(有 m 个数);
·m 秒后,所有蚯蚓的长度(有 n + m 个数)。
蛐蛐国王当然知道怎么做啦!但是他想考考你 ……
输入描述
第一行包含六个整数 n,m,q,u,v,t,其中:n,m,q 的意义见「题目描述」;u,v,t 均为正整数,你需要自己计算 (保证 0 < u < v);t 是输出参数,其含义将会在「输出描述」中解释。
第二行包含 n 个非负整数,为 a1, a2, ..., an,即初始时 n 只蚯蚓的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。
保证 。
输出描述
第一行输出 个整数,按时间顺序,依次输出第 t 秒,第 2t 秒,第 3t 秒 …… 被切断蚯蚓(在被切断前)的长度。
第二行输出 个整数,输出 m 秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第 t,第 2t,第 3t …… 的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。
请阅读样例来更好地理解这个格式。
示例1
输入
3 7 1 1 3 1 3 3 2
输出
3 4 4 4 5 5 6 6 6 6 5 5 4 4 3 2 2
说明
在神刀手到来前:3 只蚯蚓的长度为 3, 3, 2。
1 秒后:一只长度为 3 的蚯蚓被切成了两只长度分别为 1 和 2 的蚯蚓,其余蚯蚓的长度增加了 1。最终 4 只蚯蚓的长度分别为 (1, 2), 4, 3。括号表示这个位置刚刚有一只蚯蚓被切断;
2 秒后:一只长度为 4 的蚯蚓被切成了 1 和 3。5 只蚯蚓的长度分别为:2, 3, (1, 3), 4;
3 秒后:一只长度为 4 的蚯蚓被切断。6 只蚯蚓的长度分别为:3, 4, 2, 4, (1, 3);
4 秒后:一只长度为 4 的蚯蚓被切断。7 只蚯蚓的长度分别为:4, (1, 3), 3, 5, 2, 4;
5 秒后:一只长度为 5 的蚯蚓被切断。8 只蚯蚓的长度分别为:5, 2, 4, 4, (1, 4), 3, 5;
6 秒后:一只长度为 5 的蚯蚓被切断。9 只蚯蚓的长度分别为:(1, 4), 3, 5, 5, 2, 5, 4, 6;
7 秒后:一只长度为 6 的蚯蚓被切断。10 只蚯蚓的长度分别为:2, 5, 4, 6, 6, 3, 6, 5, (2, 4)。所以,7 秒内被切断的蚯蚓的长度依次为 3, 4, 4, 4, 5, 5, 6。7 秒后,所有蚯蚓长度从大到小排序为 6, 6, 6, 5, 5, 4, 4, 3, 2, 2。
示例2
输入
3 7 1 1 3 2 3 3 2
输出
4 4 5 6 5 4 3 2
说明
这个数据中只有 t = 2 与上个数据不同。只需在每行都改为每两个数输出一个数即可。
虽然第一行最后有一个 6 没有被输出,但是第二行仍然要重新从第二个数再开始输出。
备注
题解
知识点:队列。
这道题用优先队列会被卡,而用队列即可维护单调性,不需要优先队列。
首先按从大到小排序,设置一个队列存放原来的蚯蚓,两个队列分别存放分割的两部分。由于分割比例相同,而蚯蚓是从大到小选的,则分割的两部分一定能各自递减排列,只需要分别放入两个新队列的队尾即可。
每次三个队列队头找最大值,为了方便标记,一开始用队列数组创建三个队列,先从三个队列中找到任意一个非空队列标记上,然后再在三个队列中找到非空队列的队头最大值并标记,随后就得到了最大的队头所在队列的下标。
因为每次所有蚯蚓,除了这次分割的蚯蚓,都长度增加 ,一个一个加显然不合理,注意到 和时间有关,那么如果当前时间是第 秒蚯蚓原长是 ,假设蚯蚓没有切割过,那么长度就为 , 是因为第 秒只长了 秒,第 秒后才是 。
现在考虑分割的蚯蚓如何计算,因为分割需要用真实长度,因此必须先计算出真实长度 ,然后计算出新蚯蚓长度 , ,前者可以不用浮点运算,先计算 再整除 ,记得开 ,如此得到新蚯蚓的真实长度。但是,真实长度是不兼容我们对新增长度的优化的,因为如此新蚯蚓的增长时间就不一样了,有两种方案:第一种,记录新蚯蚓产生时间是第 秒,那么第 秒长度就为 ,并非 因为新切的蚯蚓在第 秒后也是不会增长的,因此实际增长时间要从第 秒开始计算到之前第 秒,一共 秒;第二种,计算新蚯蚓的假想初始长度,即假设新蚯蚓一开始就存在,求出在第 秒后(因为第 秒之前切完到第 秒后长度不变)增长到这个长度的初始长度,这样就能兼容一开始用当前时间计算长度的方式了,那么假想初始长度就是 ,因为增长了 秒一共 的长度。最后把长度分别放入两个新队列里。
因为不是每秒都输出,用一个计数器 ,记录下一次输出的时间是 的几倍, 时输出第 秒的切割蚯蚓的长度。
最后不用 排序,因为三队列都是有序的,直接归并即可,输出方式同上。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; int a[100007]; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m, q, u, v, t; cin >> n >> m >> q >> u >> v >> t; for (int i = 0;i < n;i++) cin >> a[i]; sort(a, a + n, [&](int a, int b) {return a > b;}); queue<int> Q[3]; for (int i = 0;i < n;i++) Q[0].push(a[i]); int tcnt = 1;///计时器 for (int i = 1;i <= m;i++) {///用最初长度加增长长度代表真实长度 int pos = 0; ///找到最大的蚯蚓 for (int j = 0;j < 3;j++) if (!Q[j].empty()) pos = j; for (int j = 0;j < 3;j++) if (!Q[j].empty() && Q[pos].front() < Q[j].front()) pos = j; int x = Q[pos].front() + (i - 1) * q;///第i秒的真实长度 if (i == tcnt * t)cout << x << ' ', tcnt++; Q[pos].pop(); int l = 1LL * x * u / v;///分割后的真实长度 int r = x - l; ///分割的假设最初长度,计算增长长度公式就能统一了 Q[1].push(l - i * q);///第i秒后长度为l,因此初始长度是 l - i*q Q[2].push(r - i * q);///同上 } cout << '\n'; tcnt = 1; for (int i = 1;i <= n + m;i++) {///三路归并 int pos = 0; for (int j = 0;j < 3;j++) if (!Q[j].empty()) pos = j; for (int j = 0;j < 3;j++) if (!Q[j].empty() && Q[pos].front() < Q[j].front()) pos = j; if (i == tcnt * t) cout << Q[pos].front() + m * q << ' ', tcnt++; Q[pos].pop(); } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16436816.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧