二话不说直接开干
首先,这个数据范围不小,如果使用堆或优先队列对所有的蚯蚓进行暴力维护的话将会导致
O
(
m
log
(
n
+
m
)
)
O(m\log(n+m))
O(mlog(n+m))的复杂度——这个常不好卡。
所以我们想办法找到线性复杂度的做法。
观察每次剪断后的蚯蚓,假设
a
,
b
a,b
a,b是相继两段要被剪断的蚯蚓
a
a
a被剪成
a
1
=
a
p
a_1=ap
a1=ap与
a
2
=
a
(
1
−
p
)
a_2=a(1-p)
a2=a(1−p)
b
b
b被剪成
b
1
=
(
b
+
q
)
p
b_1=(b+q)p
b1=(b+q)p与
b
2
=
(
b
+
q
)
(
1
−
p
)
b_2=(b+q)(1-p)
b2=(b+q)(1−p)
假设
p
>
1
2
p>\frac12
p>21,观察
a
1
,
b
1
a_1,b_1
a1,b1和
a
2
,
b
2
a_2,b_2
a2,b2大小关系:
当
b
1
,
b
2
b_1,b_2
b1,b2入队时,
a
1
,
a
2
a_1,a_2
a1,a2已经长长了
q
q
q
故
a
1
=
a
p
+
q
,
a
2
=
a
(
1
−
p
)
+
q
a_1=ap+q,a_2=a(1-p)+q
a1=ap+q,a2=a(1−p)+q
b
1
=
b
p
+
p
q
,
b
2
=
b
(
1
−
p
)
+
q
−
p
q
b_1=bp+pq,b_2=b(1-p)+q-pq
b1=bp+pq,b2=b(1−p)+q−pq
对于
a
1
,
b
1
a_1,b_1
a1,b1,显然
a
p
>
b
p
,
q
>
p
q
ap>bp,q>pq
ap>bp,q>pq,故
a
1
>
b
1
a_1>b_1
a1>b1
对于
a
2
,
b
2
a_2,b_2
a2,b2,同时减去
q
q
q后
a
>
b
,
−
p
q
<
0
a>b,-pq<0
a>b,−pq<0,故
a
2
>
b
2
a_2>b_2
a2>b2
所以,其实所有剪短之后的蚯蚓都是按照长短顺序单调入队的!
接下来的做法就不难了:
开三个队列
A
,
B
,
C
A,B,C
A,B,C,分别为原蚯蚓、剪断后
a
p
ap
ap部分的蚯蚓和剪断后
a
(
1
−
p
)
a(1-p)
a(1−p)的蚯蚓
先给
A
A
A排个序,然后每次从三个队列中挑一条最长的剪。
为了表现蚯蚓的生长,用一个变量
d
e
l
t
a
(
Δ
)
delta(\Delta)
delta(Δ)记录自一开始以来生长的长度
假设有两条蚯蚓
x
,
y
x,y
x,y,
x
x
x在队列中,
y
y
y是刚刚产生的,而且原始状态下
x
=
y
x=y
x=y。
x
′
x'
x′为
x
x
x在队列中储存的长度,其实际长度
x
x
x为
x
′
+
Δ
x'+\Delta
x′+Δ
在这一秒内,
y
y
y出生了,然而
x
x
x已经生长,于是我们先让
Δ
\Delta
Δ增加为
Δ
2
\Delta_2
Δ2,再使得
y
′
=
y
−
Δ
2
y'=y-\Delta_2
y′=y−Δ2
那么,现在再取出
x
x
x的话,得到的结果将是
x
′
+
Δ
2
x'+\Delta_2
x′+Δ2,即
x
+
p
x+p
x+p,而
y
y
y取出时结果仍然是
y
y
y
生长就完成了
#include<cstdio>
//#include<queue>
#include<algorithm>
#include<functional>
using namespace std;
int a[110000];long long delta;
template<typename Tp>
struct queue//超奥义玄学手打队列
{
int head,tail;
/*/For debugging
Tp list[110];
queue():head(1),tail(0){}
/*///For judging
Tp *list;
queue():head(1),tail(0),list(new Tp[11110000]){}
//*/
int size(){return tail-head+1;}
int front(){return list[head];}
void pop(){++head;}
void push(Tp x){list[++tail]=x;}
};
queue<long long>qa,qb,qc;
int getmax()
{
long long maxa=-1,maxb=-1,maxc=-1;
if(qa.size())maxa=qa.front()+delta;
if(qb.size())maxb=qb.front()+delta;
if(qc.size())maxc=qc.front()+delta;
if(maxa>=maxb&&maxa>=maxc)
/*
这地方一开始打了大于号,于是挂了好久
如果打了大于号的话会优先用c……然后两个-1就给我炸了
*/
{
qa.pop();
return maxa;
}
if(maxb>=maxa&&maxb>=maxc)//
{
qb.pop();
return maxb;
}
qc.pop();
return maxc;
}
int main()
{
int n,m,q,u,v,t;
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
sort(a+1,a+n+1,greater<int>());
for(int i=1;i<=n;i++)
qa.push(a[i]);
for(int i=1;i<=m;i++)
{
long long now=getmax();
if(i%t==0)printf("%lld ",now);
long long nowb=now*u/v,nowc=now-nowb;
if(nowb<nowc)swap(nowb,nowc);
delta+=q;
qb.push(nowb-delta);
qc.push(nowc-delta);
}
putchar(10);
for(int i=1;i<=n+m;i++)
{
long long now=getmax();
if(i%t==0)
printf("%lld ",now);
}
putchar(10);
return 0;
}