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