【算法进阶指南】蚯蚓 队列

题目链接

题意

给出 n 个蚯蚓,现在要执行 m 次切蚯蚓的操作,每次操作如下:

选择一个最长的蚯蚓 (l),如果有多个最长的,那就随便选一个,将这条蚯蚓切成两段长为
(lfloor l*p floor)(l-lfloor l*p floor) 的蚯蚓。除了这两条新增加的蚯蚓,其他的蚯蚓会增加长度 (q)

现在问 m 次切的蚯蚓长度是多少,以及 m 次操作后,所有的蚯蚓长度。

思路

题目中说除了新增的两条蚯蚓,其他的蚯蚓会都会增加长度 (q),一个一个去增加肯定不行。

可以用一个优先队列来存放蚯蚓长度,当切蚯蚓的时候,我们把新产生的蚯蚓长度减去 (i*q) ,放入优先队列中。

优先队列中的值 + ((i-1)*q)就是第 (i) 次切蚯蚓的时候,蚯蚓的长度。

这样我们就可以知道题目中要求的东西。

但是由于m太大,用优先队列复杂度有点高。

假如现在有两个蚯蚓长度分别为 (x_1)(x_2)(x_1>x_2)

第一次切完产生两条长度为 (p imes x_1)(x_1-p imes x_1)

假如说第二次切的是 (x_2),会产生两个长度为 (p imes (x_2+q))(x_2+q-p imes (x_2+q))

这时第一次切的蚯蚓长度变为了(p imes x_1+q)(x_1-p imes 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("
");
    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("
");
    return 0;
}
/*
*/
原文地址:https://www.cnblogs.com/valk3/p/13897848.html