NOIP2016 蚯蚓

时间:2020-10-21
本文章向大家介绍NOIP2016 蚯蚓,主要包括NOIP2016 蚯蚓使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

首先一个暴力的想法就是直接开一个堆来维护每一条蚯蚓,然后记录一下总体增加的长度即可。

但是这样的复杂度是 \(O(m \log m)\) 的,不足以通过本题。

但是基于观察可以发现:

  • 对于两条在 \(t, t + 1\) 时刻被砍的蚯蚓 \(i, j\),在 \(t + 2\) 时刻及以后 \(i\) 被砍的两部分会比 \(j\) 相应的被砍的两部分长。

证明如下:

只需证 \(\lfloor p(a_i + qt) \rfloor + q \ge \lfloor p(a_j + q(t + 1)) \rfloor\)

可知 \(\lfloor p(a_j + q(t + 1)) \rfloor = \lfloor p(a_j + qt) + pq \rfloor \le \lfloor p(a_j + qt) + q \rfloor = \lfloor p(a_j + qt) \rfloor + q\)

显然有 \(\lfloor p(a_i + qt) \rfloor \ge \lfloor p(a_j + qt) \rfloor + q\) 得证。

对于另一部分使用类似证明即可。

因此,每次被砍断后蚯蚓的两部分的长度都是单调递减的,那么对于这些蚯蚓咱们就不需要排序了。

那么我们只需要按照蚯蚓被砍的顺序将这些蚯蚓加入一个数组即可。

于此同时,我们需要取出当前长度最长的蚯蚓,所以还需要比较当前三个数组开头哪个元素最大。

因此,需要使用队列来维护砍断后蚯蚓的两个部分,复杂度 \(O(n \log n + m)\)

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 1e5 + 5;
const int inf = -1e9;
struct node { int t, w;} ;
int n, m, q, u, v, t, P = 1, a[N];
queue <node> Q1, Q2;
int read() {
    char c; int x = 0, f = 1;
    c = getchar();
    while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
bool cmp(int a, int b) { return a > b;}
int solve (int x) {
    int tmp;
    if(Q1.empty() && Q2.empty()) tmp = q * x + a[P], ++P;
    else if(Q2.empty()) {
        if(P > n) tmp = (x - Q1.front().t) * q + Q1.front().w, Q1.pop();
        else {
            int A = q * x + a[P], B = (x - Q1.front().t) * q + Q1.front().w;
            if(A > B) tmp = A, ++P;
            else tmp = B, Q1.pop();
        }
    }
    else if(Q1.empty()) {
        if(P > n) tmp = (x - Q2.front().t) * q + Q2.front().w, Q2.pop();
        else {
            int A = q * x + a[P], B = (x - Q2.front().t) * q + Q2.front().w;
            if(A > B) tmp = A, ++P;
            else tmp = B, Q2.pop();
        }
    }
    else {
        if(P > n) {
            int A = (x - Q1.front().t) * q + Q1.front().w, B = (x - Q2.front().t) * q + Q2.front().w;
            if(A > B) tmp = A, Q1.pop();
            else tmp = B, Q2.pop();
        }
        else {
            int A = q * x + a[P], B = (x - Q1.front().t) * q + Q1.front().w, C = (x - Q2.front().t) * q + Q2.front().w;
            int Max = max(A, max(B, C)); tmp = Max;
            if(Max == A) ++P;
            else if(Max == B) Q1.pop();
            else Q2.pop();
        }
    }
    return tmp;
}
int main() {
    n = read(), m = read(), q = read(), u = read(), v = read(), t = read();
    rep(i, 1, n) a[i] = read();
    sort(a + 1, a + n + 1, cmp);
    rep(i, 1, m) {
        int tmp = solve(i - 1); 
        if(i % t == 0) printf("%d ", tmp);
        Q1.push((node){i, 1ll * tmp * u / v}), Q2.push((node){i, tmp - 1ll * tmp * u / v});
    }
    puts("");
    rep(i, 1, n + m) {
        int tmp = solve(m);
        if(i % t == 0) printf("%d ", tmp);
    }
    return 0;
}

当每次操作涉及比大小以及添加一些数继续比大小的时候,往往加入的数会具有单调性,这样就不需要额外比较了。

原文地址:https://www.cnblogs.com/Go7338395/p/13855190.html