【NOIP2016提高组】蚯蚓
https://www.luogu.org/problem/show?pid=2827
首先考虑暴力:
每次都是拿最长的蚯蚓,容易想到用堆。
每次除拿出来的以外所有的蚯蚓都增长,容易想到用一个懒惰标记来记录所有的蚯蚓增长了多少。取最大的元素出来后加上标记的值,放元素进去的时候减去标记的值。
这时已经可以骗到60分了。
假设某一次取出来的元素长度为x,当前标记的值为inc,切完以后放进去的就是(x+inc)p-(inc+q)、(x+inc)(1-p)-(inc+q)两个元素
由于
(x+inc)p-(inc+q)-x=(x+inc)p-(x+inc)-q=(p-1)(x+inc)-q<0
(x+inc)(1-p)-(inc+q)-x=(x+inc)(1-p)-(x+inc)-q=-p(x+inc)-q<0
可知放进去的两个元素必定都小于刚取出来的元素,也就是每次放进去的两个元素依次递减。
因此可以开三个队列,第一个队列存放降序排序后的初始值,剩余两个队列分别存放每次切出来的两个元素。可以保证这三个队列都是单调递减的。每次比较三个队列的头元素,取最大的。
因为STL自带队列在不开优化的NOIP里比较慢,所以最好手写队列。
#include <cmath> #include <iostream> #include <queue> #include <algorithm> #include <functional> template <class T> struct myqueue { #define maxlength 8000005 T data[maxlength]; int p[2] = {0, 0}; // 头尾指针 int size = 0; void push(T val) { size++; data[p[1]] = val; if (++p[1] >= maxlength) p[1] -= maxlength; } void pop() { size--; if (++p[0] >= maxlength) p[0] -= maxlength; } T front() { return data[p[0]]; } bool empty() { return size == 0; } }; #define maxn 100005 using namespace std; int n, m, q, t; long double p, eps = 1e-6; myqueue<int> x, y, z; int increase = 0; int pop_max() { int from = 0; int ew = -10000000; if (!x.empty() && x.front() + increase > ew) { from = 1; ew = x.front() + increase; } if (!y.empty() && y.front() + increase > ew) { from = 2; ew = y.front() + increase; } if (!z.empty() && z.front() + increase > ew) { from = 3; ew = z.front() + increase; } switch (from) { case 1: x.pop(); break; case 2: y.pop(); break; case 3: z.pop(); break; } return ew; } int tmp[maxn]; int main() { ios::sync_with_stdio(false); int a, b; cin >> n >> m >> q >> a >> b >> t; p = a * 1.0 / b; for (int i = 1; i <= n; i++) cin >> tmp[i]; sort(tmp + 1, tmp + 1 + n, greater<int>()); for (int i = 1; i <= n; i++) x.push(tmp[i]); int ew; for (int i = 1; i <= m; i++) { ew = pop_max(); a = ew * p + eps; b = ew - a; if (i % t == 0) cout << ew << ' '; increase += q; y.push(a - increase); z.push(b - increase); } cout << endl; for (int i = 1; i <= m + n; i++) { ew = pop_max(); if (i % t == 0) cout << ew << ' '; } cout << endl; return 0; }