题意:
相当于维护一个集合,支持查询最大值、删除最大值、插入新的值。时间卡的贼紧!!!!!!!!!!我不记得我T了几次了都
思路:
根据输入输出以及n、m的数据范围可以知道,需要在每秒进行切割时找出当前最大值,这时发现枚举和堆、单调队列等查找/维护最大值的方法是超时的。这时就有三个队列q1、q2和q3,如果q1开始时单调递减,每次取出最大值,然后将这个蚯蚓分开,把其中大的一部分压入q2,小的一部分压入q3,显然,此时q1、q2和q3都是单调递减的(所以每次的取出操作就可以是:在q1、q2、q3的队首取出最大的一个)。
这时你会产生一个新疑问:怎样让蚯蚓生长呢?
我们发现,暴力将每次每只蚯蚓的长度加上q是不现实的,所以定义一个del,用来表示蚯蚓增长的长度,del初始时为零,每过一秒加上一个q。然后我们可以这样想:在每一秒初,最长的蚯蚓被切开;在这一秒过程中,其他蚯蚓增长了q;在这一秒末,最长的蚯蚓被切成两半,分别压入数组中:
为什么是一个加del和一个减del的操作呢?数学证明:如果第a秒(此时del=(a-1)q)初取出一个长为s的蚯蚓,那么它的实际长度是(s+(a-1)q),它会被切成两半s1和s2在第a+1末被放回去,s1、s2就是这两条新蚯蚓的初始长度,而放回去的是s1-a×q和s2-a×q。如果在第b+1秒初s1-a×q被取了出来,这时它会加上b×q成为s1-a×q+b×q。而在第a秒末到第b+1秒初中间有b-a秒,s1的长度应该是初始长度s1加上增加的长度(b-a)q,即s1+(b-a)q=s1-a×q+b×q。说白了就是让s1,s2把给他们吃的q吐出来。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 7e6+10;
inline int read() {
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
int n,m,q,u,v,t,del;
int h=1,h1=1,h2=1,t1,t2;
int s[N],c1[N],c2[N];
priority_queue<int> pq;
bool cmp(int a,int b) {
return a > b;
}
int main()
{
n = read(), m = read(), q = read(), u = read() ,v = read() ,t = read();
double p = (double)u/(double)v;
for(int i=1;i<=n;++i) s[i] = read();
sort(s+1, s+1+n, cmp);//第一个队列用初始元素从小到大排序
for(int i=1;i<=m;++i) {
int tp,a1,a2;//tp为从三个队列头中选到的最大值
if(h > n-1) c1[h1]>c2[h2] ? tp=c1[h1++] : tp=c2[h2++];//每只蚯蚓都被切过才比较
else if(s[h]>=c1[h1] && s[h]>=c2[h2]) tp = s[h++];
else if(s[h]<=c1[h1] && c2[h2]<=c1[h1]) tp = c1[h1++];
else tp = c2[h2++];
tp += del; a1 = floor(p*(double)tp); a2 = tp - a1;//先加del再切模拟所有都长长了del
del += q; a1 -= del; a2 -= del;
c1[++t1] = a1, c2[++t2] = a2;//c1,c2存切完后的
if(i%t==0) printf("%d ",tp);
}
putchar('\n');
//把结果弄在优先队列里输出
for(int i=h;i<=n;++i) pq.push(s[i]);
for(int i=h1;i<=t1;++i) pq.push(c1[i]);
for(int i=h2;i<=t2;++i) pq.push(c2[i]);
int i = 0;
while(pq.size()) {
++i;
if(i%t==0) printf("%d ",pq.top()+del);
pq.pop();
}
return 0;
}