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


    题目链接

    题意

    给出 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;
    }
    /*
    */
    
  • 相关阅读:
    python:利用asyncio进行快速抓取
    os.path.exists(path) 和 os.path.lexists(path) 的区别
    isdigit()判断是不是数字
    switf资源
    51cto培训课程
    51cto运维培训课程
    Python: 在Unicode和普通字符串之间转换
    VC++ CopyFile函数使用方法
    Eclipse断点调试
    AFNetworking2.0后 进行Post请求
  • 原文地址:https://www.cnblogs.com/valk3/p/13897848.html
Copyright © 2020-2023  润新知