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[] = {, }; // 頭尾指標
int size = ;
void push(T val)
{
size++;
data[p[]] = val;
if (++p[] >= maxlength)
p[] -= maxlength;
}
void pop()
{
size--;
if (++p[] >= maxlength)
p[] -= maxlength;
}
T front()
{
return data[p[]];
}
bool empty()
{
return size == ;
}
}; #define maxn 100005
using namespace std;
int n, m, q, t;
long double p, eps = 1e-;
myqueue<int> x, y, z;
int increase = ;
int pop_max()
{
int from = ;
int ew = -;
if (!x.empty() && x.front() + increase > ew)
{
from = ;
ew = x.front() + increase;
}
if (!y.empty() && y.front() + increase > ew)
{
from = ;
ew = y.front() + increase;
}
if (!z.empty() && z.front() + increase > ew)
{
from = ;
ew = z.front() + increase;
}
switch (from)
{
case :
x.pop();
break;
case :
y.pop();
break;
case :
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 = ; i <= n; i++)
cin >> tmp[i];
sort(tmp + , tmp + + n, greater<int>());
for (int i = ; i <= n; i++)
x.push(tmp[i]); int ew;
for (int i = ; i <= m; i++)
{
ew = pop_max();
a = ew * p + eps;
b = ew - a;
if (i % t == )
cout << ew << ' ';
increase += q;
y.push(a - increase);
z.push(b - increase);
}
cout << endl;
for (int i = ; i <= m + n; i++)
{
ew = pop_max();
if (i % t == )
cout << ew << ' ';
}
cout << endl;
return ;
}