题目大意:
让我们定义A 为1, 2, 3,。。。, 2 * N - 1 的一个全排列。
定义数列B 为A 的前缀的中位数形成的数列:B[i] 为A[1],A[2],。。。,A[2 * i - 1] 的中位数。
注:对于M 个数的中位数(M 是奇数),可以通过排序后取中间的数得到。
给出N 和数列B。找到一个全排列A 使得前缀中位数形成的数列恰好为B。
• 1 <= A[i] <= 2 * N - 1,对于任意i 从1 到2 * N - 1
• 1 <= B[i] <= 2 * N - 1,对于任意i 从1 到N
• 1 <= N <= 100 000
• 60% 的数据有N <= 1000
题解:
据说是权值线段树,不过呢,可以贪心。
啥,可以贪心?没错。
我们发现因为是一定有解的,所以我们分类讨论:
对于一个给出的bi:
(1)bi在A中已经出现过:
①bi>b[i-1]:
则输出2个能放的最大的数,因为题目满足一定有解,且你大于中位数,所以要放数使得它左移
②bi<b[i-1]:
则输出2个能放的最小的数,原因同①
③bi=b[i-1]:
则输出1个能放的最大的数与1个能放的最小的数,这样使得它继续平衡,从而使得中位数不变
(2)bi还没有在A中出现过:
先输出bi 没有bi这个数哪来的中位数?
然后对于一个bi,
①bi>b[i-1]:
则放一个当前还能放的最大的数
因为你在前2*(i-1)个数的中位数b[i-1]的右边,你要使得它平衡你的bi才能成为中位数
②bi<b[i-1]:
则放一个当前还能放的最小的数
因为你在前2*(i-1)个数的中位数b[i-1]的左边,你要使得它平衡你的bi才能成为中位数
③bi=b[i-1]:
你的bi都没出现过,有可能么?
时间复杂度:O(2n-1)
代码:
Download
var
f:array [0..200001] of boolean;
a:array [0..100001] of longint;
l,r,n,m,i,j:longint;
begin
assign(input,'medians.in'); reset(input);
assign(output,'medians.out');rewrite(output);
readln(n);
read(a[1]);
write(a[1],' ');
f[a[1]]:=true;
l:=1; r:=2*n-1;
for i:=2 to n do
begin
read(a[i]);
if f[a[i]] then
begin
if a[i]>a[i-1] then
begin
write(r,' ');
f[r]:=true;
while f[r] do dec(r);
write(r,' ');
f[r]:=true;
while f[r] do dec(r);
end
else if a[i]<a[i-1] then
begin
write(l,' ');
f[l]:=true;
while f[l] do inc(l);
write(l,' ');
f[l]:=true;
while f[l] do inc(l);
end
else begin
write(l,' ',r,' ');
f[l]:=true;
f[r]:=true;
while f[l] do inc(l);
while f[r] do dec(r);
end;
end
else begin
f[a[i]]:=true;
while f[l] do inc(l);
while f[r] do dec(r);
write(a[i],' ');
if a[i]>a[i-1]
then begin
write(r,' ');
f[r]:=true;
while f[r] do dec(r);
end
else begin
write(l,' ');
f[l]:=true;
while f[l] do inc(l);
end;
end;
end;
close(input); close(output);
end.