【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;
}

 

posted @ 2017-09-16 10:44  ssttkkl  阅读(458)  评论(0编辑  收藏  举报