【算法进阶指南】蚯蚓 队列
题意
给出 n 个蚯蚓,现在要执行 m 次切蚯蚓的操作,每次操作如下:
选择一个最长的蚯蚓 \(l\),如果有多个最长的,那就随便选一个,将这条蚯蚓切成两段长为
\(\lfloor l*p \rfloor\),\(l-\lfloor l*p \rfloor\) 的蚯蚓。除了这两条新增加的蚯蚓,其他的蚯蚓会增加长度 \(q\)。
现在问 m 次切的蚯蚓长度是多少,以及 m 次操作后,所有的蚯蚓长度。
思路
题目中说除了新增的两条蚯蚓,其他的蚯蚓会都会增加长度 \(q\),一个一个去增加肯定不行。
可以用一个优先队列来存放蚯蚓长度,当切蚯蚓的时候,我们把新产生的蚯蚓长度减去 \(i*q\) ,放入优先队列中。
优先队列中的值 + \((i-1)*q\)就是第 \(i\) 次切蚯蚓的时候,蚯蚓的长度。
这样我们就可以知道题目中要求的东西。
但是由于m太大,用优先队列复杂度有点高。
假如现在有两个蚯蚓长度分别为 \(x_1\) ,\(x_2\), \(x_1>x_2\)
第一次切完产生两条长度为 \(p \times x_1\),\(x_1-p\times x_1\)
假如说第二次切的是 \(x_2\),会产生两个长度为 \(p \times (x_2+q)\),\(x_2+q-p\times (x_2+q)\)
这时第一次切的蚯蚓长度变为了\(p \times x_1+q\),\(x_1-p\times x_1+q\)
可以看出 \(x_1\)切过的长度是大于\(x_2\)切过的长度的。
那么也就是新产生的蚯蚓的长度是单调递减的。
我们就可以用三个队列分别维护,原来 \(n\) 个蚯蚓的长度,和新产生的两个蚯蚓的长度。
每次取三个队列的头部的最大值。
配合优先队列的思路。
复杂度为 \(O(m+nlog n)\)
代码
#include <algorithm>
#include <queue>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <vector>
#define pb push_back
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
using namespace std;
vector<int> ans;
int cmp(int a, int b)
{
return a > b;
}
int arr[N];
queue<int> q1, q2, q3;
int main()
{
int n, m, q, u, v, t;
scanf("%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t);
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
}
sort(arr + 1, arr + 1 + n);
for (int i = n; i; i--) {
q1.push(arr[i]);
}
for (int i = 1; i <= m; i++) {
int now = -inf;
if (!q1.empty()) {
now = q1.front();
}
if (!q2.empty()) {
now = max(now, q2.front());
}
if (!q3.empty()) {
now = max(now, q3.front());
}
if (!q1.empty() && now == q1.front()) {
q1.pop();
} else if (!q2.empty() && now == q2.front()) {
q2.pop();
} else {
q3.pop();
}
now += (i - 1) * q;
if (i % t == 0) {
printf("%d ", now);
}
int temp = int(1LL * u * now / v);
q2.push(temp - i * q), q3.push(now - temp - i * q);
}
printf("\n");
while (!q1.empty()) {
ans.pb(q1.front());
q1.pop();
}
while (!q2.empty()) {
ans.pb(q2.front());
q2.pop();
}
while (!q3.empty()) {
ans.pb(q3.front());
q3.pop();
}
sort(ans.begin(), ans.end(), cmp);
for (int i = t; i <= ans.size(); i += t) {
printf("%d ", ans[i - 1] + m * q);
}
printf("\n");
return 0;
}
/*
*/