洛谷 P1309 瑞士轮
题目描述
2*N 名编号为 1~2N 的选手共进行R 轮比赛。每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。
每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1 名和第2 名、第 3 名和第 4名、……、第2K – 1 名和第 2K名、…… 、第2N – 1 名和第2N名,各进行一场比赛。每场比赛胜者得1 分,负者得 0 分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。
现给定每个选手的初始分数及其实力值,试计算在R 轮比赛过后,排名第 Q 的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。
分析
首先我们一定要快排一下分数。
然而如果全程用快排交上去的话,应该会是有超时的(没超时证明数据太弱了)
但我们可以很简单的看出来,如果每次一对对输赢的话,是不是有点眼熟呢?没错,就是归并。
归并如下代码自己看吧。
type swiss=record score,number,strong:longint; end;
var
n,r,q,i,j:longint;
t:swiss;
a:array[1..200000]of swiss;
win,lose:array[1..100000]of swiss;
procedure quicksort(low,high:longint);
var
i,j:longint;
mid,temp:swiss;
begin
i:=low;j:=high;mid:=a[(low+high)div 2];
repeat
while (a[i].score>mid.score)or(a[i].score=mid.score)and(a[i].number<mid.number) do inc(i);
while (a[j].score<mid.score)or(a[j].score=mid.score)and(a[j].number>mid.number) do dec(j);
if i<=j then
begin
temp:=a[i];a[i]:=a[j];a[j]:=temp;
inc(i);dec(j);
end;
until i>j;
if i<high then quicksort(i,high);
if low<j then quicksort(low,j);
end;
procedure gb;
var
l1,l2,m,i:longint;
begin
l1:=1;l2:=1;m:=1;
while (l1<=n)and(l2<=n) do
if (win[l1].score>lose[l2].score)or(win[l1].score=lose[l2].score)and(win[l1].number<lose[l2].number) then
begin
a[m]:=win[l1];
inc(l1);
inc(m);
end
else
begin
a[m]:=lose[l2];
inc(l2);
inc(m);
end;
for i:=l1 to n do begin a[m]:=win[i];inc(m); end;
for i:=l2 to n do begin a[m]:=lose[i];inc(m); end;
end;
begin
readln(n,r,q);
for i:=1 to 2*n do
begin read(a[i].score);a[i].number:=i; end;
for i:=1 to 2*n do
read(a[i].strong);
quicksort(1,2*n);
for i:=1 to r do
begin
for j:=1 to n do
if a[j*2].strong>a[j*2-1].strong then
begin
inc(a[j*2].score);
win[j]:=a[j*2];
lose[j]:=a[j*2-1];
end
else
begin
inc(a[j*2-1].score);
win[j]:=a[j*2-1];
lose[j]:=a[j*2];
end;
gb;
end;
writeln(a[q].number);
end.