NC16430 [NOIP2016]蚯蚓

题目

题目描述

本题中,我们将用符号 c 表示对 c 向下取整,例如:3.0=3.1=3.9=3
蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。
蛐蛐国里现在共有 n 只蚯蚓(n 为正整数)。每只蚯蚓拥有长度,我们设第 i 只蚯蚓的长度为 ai(i=1,2,,n),并保证所有的长度都是非负整数(即:可能存在长度为 0 的蚯蚓)。
每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数 p(是满足 0 < p < 1 的有理数)决定,设这只蚯蚓长度为 x,神刀手会将其切成两只长度分别为 pxxpx 的蚯蚓。特殊地,如果这两个数的其中一个等于 0,则这个长度为 0 的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加 q(是一个非负整常数)。
蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 m 秒才能到来 ……(m 为非负整数)
蛐蛐国王希望知道这 m 秒内的战况。具体来说,他希望知道:

·m 秒内,每一秒被切断的蚯蚓被切断前的长度(有 m 个数);

·m 秒后,所有蚯蚓的长度(有 n + m 个数)。

蛐蛐国王当然知道怎么做啦!但是他想考考你 ……

输入描述

第一行包含六个整数 n,m,q,u,v,t,其中:n,m,q 的意义见「题目描述」;u,v,t 均为正整数,你需要自己计算 p=uv(保证 0 < u < v);t 是输出参数,其含义将会在「输出描述」中解释。
第二行包含 n 个非负整数,为 a1, a2, ..., an,即初始时 n 只蚯蚓的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。
保证 1n1050<m<7x1060<u<v<1090q2001<t<710<ai<108

输出描述

第一行输出 mt 个整数,按时间顺序,依次输出第 t 秒,第 2t 秒,第 3t 秒 …… 被切断蚯蚓(在被切断前)的长度。
第二行输出 (n+m)t个整数,输出 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 没有被输出,但是第二行仍然要重新从第二个数再开始输出。

备注

1n105,0m7×106,1t71,0ai108,1v109,0q200

题解

知识点:队列。

这道题用优先队列会被卡,而用队列即可维护单调性,不需要优先队列。

首先按从大到小排序,设置一个队列存放原来的蚯蚓,两个队列分别存放分割的两部分。由于分割比例相同,而蚯蚓是从大到小选的,则分割的两部分一定能各自递减排列,只需要分别放入两个新队列的队尾即可。

每次三个队列队头找最大值,为了方便标记,一开始用队列数组创建三个队列,先从三个队列中找到任意一个非空队列标记上,然后再在三个队列中找到非空队列的队头最大值并标记,随后就得到了最大的队头所在队列的下标。

因为每次所有蚯蚓,除了这次分割的蚯蚓,都长度增加 q ,一个一个加显然不合理,注意到 q 和时间有关,那么如果当前时间是第 i 秒蚯蚓原长是 len,假设蚯蚓没有切割过,那么长度就为 len+(i1)qi1 是因为第 i 秒只长了 i1 秒,第 i 秒后才是 i

现在考虑分割的蚯蚓如何计算,因为分割需要用真实长度,因此必须先计算出真实长度 x ,然后计算出新蚯蚓长度 l=xuvr=lx ,前者可以不用浮点运算,先计算 xu 再整除 v ,记得开 long long ,如此得到新蚯蚓的真实长度。但是,真实长度是不兼容我们对新增长度的优化的,因为如此新蚯蚓的增长时间就不一样了,有两种方案:第一种,记录新蚯蚓产生时间是第 k 秒,那么第 i 秒长度就为 len+(i1k)q ,并非 k1 因为新切的蚯蚓在第 k 秒后也是不会增长的,因此实际增长时间要从第 k+1 秒开始计算到之前第 i 秒,一共 ik1 秒;第二种,计算新蚯蚓的假想初始长度,即假设新蚯蚓一开始就存在,求出在第 i 秒后(因为第 i 秒之前切完到第 i 秒后长度不变)增长到这个长度的初始长度,这样就能兼容一开始用当前时间计算长度的方式了,那么假想初始长度就是 leniq ,因为增长了 i 秒一共 iq 的长度。最后把长度分别放入两个新队列里。

因为不是每秒都输出,用一个计数器 tcnt,记录下一次输出的时间是 t 的几倍,i==tcntt 时输出第 tcntt 秒的切割蚯蚓的长度。

最后不用 sort 排序,因为三队列都是有序的,直接归并即可,输出方式同上。

时间复杂度 O(nlogn+m)

空间复杂度 O(n)

代码

#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;
}
posted @   空白菌  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示