P2827 [NOIP2016 提高组] 队列

题意

传送门 P2827 [NOIP2016 提高组] 蚯蚓

题解

容易想到使用二叉堆维护长度的最大值,由于每次新产生之外的蚯蚓长度都增加 q q q,而难以修改已经在堆中的元素,那么对新产生的蚯蚓长度减 q q q,可以使长度的相互关系保持不变。时间复杂度 O ( m log ⁡ n ) O(m\log n) O(mlogn),显然难以胜任。

设当前切割蚯蚓长度为 x 1 x_1 x1,那么新增蚯蚓长度分别为 ⌊ p x 1 ⌋ \lfloor px_1\rfloor px1 x 1 − ⌊ p x 1 ⌋ x_1-\lfloor px_1\rfloor x1px1。那么下一次可能的切割蚯蚓显然为之前未切割的蚯蚓的长度最大值与新增蚯蚓长度,假设下一次切割的蚯蚓长度为 x 2 x_2 x2,那么有 x 1 ≥ x 2 x_1\geq x_2 x1x2,且满足

{ ⌊ p x 1 ⌋ + q = ⌊ p x 1 + q ⌋ ≥ ⌊ p ( x 2 + q ) ⌋ x 1 − ⌊ p x 1 ⌋ + q ≥ x 1 − ⌊ p ( x 1 + q ) ⌋ + q ≥ x 2 − ⌊ p ( x 2 + q ) ⌋ + q \begin{cases} \lfloor px_1\rfloor+q=\lfloor px_1+q\rfloor\geq \lfloor p(x_2+q)\rfloor \\ x_1-\lfloor px_1\rfloor+q\geq x_1-\lfloor p(x_1+q)\rfloor+q\geq x_2-\lfloor p(x_2+q)\rfloor+q\\ \end{cases} {px1+q=px1+qp(x2+q)x1px1+qx1p(x1+q)+qx2p(x2+q)+q 2 2 2 个不等式中 x − ⌊ p ( x + q ) ⌋ , x ∈ Z + x-\lfloor p(x+q)\rfloor,x\in \Z^+ xp(x+q),xZ+ 的单调性可通过将整数 x x x 移入取整符号进行证明,已知 0 < 1 − p < 1 0<1-p<1 0<1p<1,那么有
x 1 − ⌊ p ( x 1 + q ) ⌋ ≥ ⌊ ( 1 − p ) x 1 − p q ) ⌋ ≥ ⌊ ( 1 − p ) x 2 − p q ) ⌋ ≥ x 2 − ⌊ p ( x 2 + q ) ⌋ x_1-\lfloor p(x_1+q)\rfloor\geq \lfloor (1-p)x_1-pq)\rfloor\geq \lfloor (1-p)x_2-pq)\rfloor\geq x_2-\lfloor p(x_2+q)\rfloor x1p(x1+q)(1p)x1pq)(1p)x2pq)x2p(x2+q) 证明了每一次新增的蚯蚓长度 ⌊ p ( x 2 + q ) ⌋ \lfloor p(x_2+q)\rfloor p(x2+q) x 2 − ⌊ p ( x 2 + q ) ⌋ + q x_2-\lfloor p(x_2+q)\rfloor+q x2p(x2+q)+q 分别不大于上一次切割新增的 ⌊ p x 1 ⌋ + q \lfloor px_1\rfloor+q px1+q x 1 − ⌊ p x 1 ⌋ + q x_1-\lfloor px_1\rfloor+q x1px1+q。那么可以建立 3 3 3 个队列,分别维护有序的初始值、新增的 ⌊ p x 1 ⌋ \lfloor px_1\rfloor px1 部分与 x 1 − ⌊ p x 1 ⌋ x_1-\lfloor px_1\rfloor x1px1 部分,此时各队列保持有序,下一次切割长度为 3 3 3 个队首元素的最大值。时间复杂度 O ( n log ⁡ n + m ) O(n\log n + m) O(nlogn+m)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005, maxm = 7000005, inf = 0x7fffffff;
int A[maxn], cut[maxm], rem[maxm + maxn];
queue<int> X, Y, Z;

int get()
{
    int x = X.size() ? X.front() : -inf, k = 0;
    if (Y.size() && Y.front() > x)
        x = Y.front(), k = 1;
    if (Z.size() && Z.front() > x)
        x = Z.front(), k = 2;
    if (k == 0)
        X.pop();
    else if (k == 1)
        Y.pop();
    else
        Z.pop();
    return x;
}

int main()
{
    int n, m, q, u, v, t;
    scanf("%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t);
    double p = (double)u / v;
    for (int i = 1; i <= n; ++i)
        scanf("%d", A + i);
    sort(A + 1, A + n + 1);
    for (int i = n; i; --i)
        X.push(A[i]);
    int d = 0;
    for (int i = 1; i <= m; ++i)
    {
        int x = get() + d;
        cut[i] = x;
        d += q;
        int y = x * p, z = x - y;
        Y.push(y - d);
        Z.push(z - d);
    }
    for (int i = 1; i <= n + m; ++i)
        rem[i] = get() + d;
    for (int i = t; i <= m; i += t)
        printf("%d ", cut[i]);
    puts("");
    for (int i = t; i <= m + n; i += t)
        printf("%d ", rem[i]);
    puts("");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值