[NOIP2016提高]蚯蚓 题解
题目地址:洛谷:【P2827】蚯蚓 – 洛谷
题目描述
本题中,我们将用符号 $\lfloor c \rfloor$ 表示对 c 向下取整,例如: $\lfloor 3.0 \rfloor = \lfloor 3.1 \rfloor = \lfloor 3.9 \rfloor = 3$。
蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。
蛐蛐国里现在共有 n 只蚯蚓( n 为正整数)。每只蚯蚓拥有长度,我们设第 i 只蚯蚓的长度为 ai ( i = 1, 2, … , n ),并保证所有的长度都是非负整数(即:可能存在长度为0的蚯蚓)。
每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数 p (是满足 0 < p < 1 的有理数)决定,设这只蚯蚓长度为 x ,神刀手会将其切成两只长度分别为 $\lfloor px \rfloor$ 和 $\lfloor x – px \rfloor$ 的蚯蚓。特殊地,如果这两个数的其中一个等于 0 ,则这个长度为 0 的蚯蚓也会被保留。此 外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加 q(是一个非负整常数)。
蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐 蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 m 秒才能到来……(m 为非负整数)蛐蛐国王希望知道这 m 秒内的战况。
具体来说,他希望知道:
- m 秒内,每一秒被切断的蚯蚓被切断前的长度(有 m 个数);
- m 秒后,所有蚯蚓的长度(有 n + m 个数)。
蛐蛐国王当然知道怎么做啦! 但是他想考考你……
输入输出格式
输入格式:
第一行包含六个整数 n, m, q, u, v, t ,其中: n, m, q 的意义见【问题描述】; u, v, t 均 为正整数;你需要自己计算 p = u/v (保证 0 < u < v );t 是输出参数,其含义将会在【输出格式】中解释。
第二行包含 n 个非负整数,为 a1, a2, … , an ,即初始时 n 只蚯蚓的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。
保证 1 ≤ n ≤ 10^5 , 0 ≤ m ≤ 7 × 10^6 , 0 < u < v ≤ 10^9 , 0 ≤ q ≤ 200 , 1 ≤ t ≤ 71 ,
0 ≤ ai ≤ 10^8 。
输出格式:
第一行输出$\left\lfloor \frac{m}{t} \right\rfloor$个整数,按时间顺序,依次输出第 t秒,第 2t 秒,第 3t 秒,……被切 断蚯蚓(在被切断前)的长度。
第二行输出$\left\lfloor \frac{n+m}{t} \right\rfloor$个整数,输出 m 秒后蚯蚓的长度:需要按从大到小的顺序,依次输出排名第 t ,第 2t ,第 3t ,……的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。
请阅读样例来更好地理解这个格式。
输入输出样例
输入样例#1:
3 7 1 1 3 1 3 3 2
输出样例#1:
3 4 4 4 5 5 6 6 6 6 5 5 4 4 3 2 2
输入样例#2:
3 7 1 1 3 2 3 3 2
输出样例#2:
4 4 5 6 5 4 3 2
输入样例#3:
3 7 1 1 3 9 3 3 2
输出样例#3:
2
说明
题解
很容易想到用三个堆来维护原来的蚯蚓、切后的两段蚯蚓,通过一定的修正将堆内的各个元素统一至某一时间点(如,最开始的长度),便于堆内元素值的比较。可以用当前值-当前秒数作为修正值。
在这种做法的基础上,我们观察到,由于每次都是取最大的来切,切后的两段蚯蚓分别对应的两个序列内部实际上有随时间递增而不减的单调性。我们直接将堆换为队列即可得到本题的正解。
正解复杂度$O(m)$。
代码
// Code by KSkun, 2018/11
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <functional>
#include <vector>
typedef long long LL;
inline char fgc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
? EOF : *p1++;
}
inline LL readint() {
register LL res = 0, neg = 1; register char c = fgc();
for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
return res * neg;
}
inline char readsingle() {
register char c;
while(!isgraph(c = fgc())) {}
return c;
}
const int MAXN = 100005, MAXM = 7000005;
int n, m, q, u, v, t, a[MAXN];
double p;
std::vector<int> vec;
struct Queue {
int l, r, a[MAXM];
Queue(): l(1), r(1) {}
inline void push(int x) {
a[r++] = x;
}
inline void pop() {
if(l >= r) return; l++;
}
inline int query(int p, int t) {
if(l >= r) return -1;
return a[l] + (p - 1) * q * (1 - t) + (p - l - 1) * q * t;
}
inline bool empty() {
return l >= r;
}
} que[3];
inline void query(int x, int &res, int &t) {
int r1 = que[0].empty() ? -1 : que[0].query(x, 0),
r2 = que[1].empty() ? -1 : que[1].query(x, 1),
r3 = que[2].empty() ? -1 : que[2].query(x, 1);
if(r1 > res) {
res = r1; t = 0;
}
if(r2 > res) {
res = r2; t = 1;
}
if(r3 > res) {
res = r3; t = 2;
}
}
int main() {
n = readint(); m = readint(); q = readint();
u = readint(); v = readint(); t = readint();
p = double(u) / v;
for(int i = 1; i <= n; i++) a[i] = readint();
std::sort(a + 1, a + n + 1, std::greater<int>());
for(int i = 1; i <= n; i++) que[0].push(a[i]);
for(int i = 1; i <= m; i++) {
int res = -1, t = -1;
query(i, res, t);
if(i % ::t == 0) printf("%d ", res);
que[t].pop();
que[1].push(floor(p * res));
que[2].push(res - floor(p * res));
}
puts("");
while(!que[0].empty()) {
vec.push_back(que[0].query(m + 1, 0));
que[0].pop();
}
while(!que[1].empty()) {
vec.push_back(que[1].query(m + 1, 1));
que[1].pop();
}
while(!que[2].empty()) {
vec.push_back(que[2].query(m + 1, 1));
que[2].pop();
}
std::sort(vec.begin(), vec.end(), std::greater<int>());
for(int i = 0; i < vec.size(); i++) {
if((i + 1) % t == 0) printf("%d ", vec[i]);
}
return 0;
}