4866: 瑞士轮 归并排序

描述

 

 

2*N名编号为1~2N的选手共进行R轮比赛。每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。

每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1名和第2名、第3名和第4名、……、第2K-1名和第2K名、……、第2N-1名和第2N名,各进行一场比赛。每场比赛胜者得 1分,负者得0分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。

现给定每个选手的初始分数及其实力值,试计算在R轮比赛过后,排名第Q的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。

 

 

 

输入

 

 

输入的第一行是三个正整数N、R、Q,每两个数之间用一个空格隔开,表示有2*N名选手、R轮比赛,以及我们关心的名次Q。

第二行是2*N个非负整数s1,s2,…,s2N,每两个数之间用一个空格隔开,其中si表示编号为i的选手的初始分数。

第三行是2*N个正整数w1,w2,…,w2N,每两个数之间用一个空格隔开,其中wi表示编号为i的选手的实力值。

1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s1, s2, …, s2N≤108,1 ≤w1, w2 , …, w2N≤ 108

1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s_1, s_2, …, s_{2N}≤10^8,1 ≤w_1, w_2 , …, w_{2N}≤ 10^

 

 

输出

 

 

输出只有一行,包含一个整数,即R轮比赛结束后,排名第Q的选手的编号。

 

 

样例输入

 

2 4 2
7 6 6 7
10 5 20 15

样例输出

1

▶用数组依次表示选手编号,当前得分,实力值

▶编写cmp函数,先对选手按照初始分数从大到小排列,分数相同者编号从小到大排列

▶每轮赛后用归并排序(merge函数)对所有选手进行排序。分成胜者组和败者组,此时两个数组一定都按照分数由大到小排列,因此比较两数组的最大值,分数高者加进总序列,分数低者继续和另一个数组的次高值比较,分数高者再加进总序列。直到两个数组的元素都加进总序列。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6+10,inf = 0x3f3f3f3f;
int n,r,q;
int s[N],w[N]; //s初识分数,w实力 
int a[N],win[N],lose[N];//a编号, win每局胜利下标,lose失败下标
bool cmp(int x,int y)
{
    if(s[x]==s[y])return x<y;
    return s[x]>s[y];
} 
void split()
{
    win[0] = lose[0] = 0;
    for(int i = 1; i <= n; i+=2) //相邻选手比赛每次+2
    {
        if(w[a[i]] > w[a[i+1]])
        {
            s[a[i]]++;
            win[++win[0]] = a[i];
            lose[++lose[0]] = a[i+1];
        }
        else
        {
            s[a[i+1]]++;
            win[++win[0]] = a[i+1];
            lose[++lose[0]] = a[i];
        }
    }
}
void merge() //归并,使有序的win,lose归并到a
{
    int i,j;
    i = j = 1, a[0] = 0;//k记录a[]中有多少个数
    while(i <= win[0] && j<=lose[0])
    {
        if(cmp(win[i], lose[j]))a[++a[0]] = win[i++];
        else a[++a[0]] = lose[j++];
    } 
    while(i <= win[0])a[++a[0]] = win[i++];//若败者组已全部加进序列,胜者组有剩则依次加进总序列
    while(j <= lose[0]) a[++a[0]] = lose[j++];//若胜者组已全部加进序列,败者组依次进总序列
} 
int main()
{
    cin >> n >> r >> q; n*=2;
    for(int i = 1; i <= n; i++) a[i] = i;
    for(int i = 1; i <= n; i++) cin >> s[i];
    for(int i = 1; i <= n; i++) cin >> w[i];
    sort(a + 1, a + n + 1, cmp); //将选手按照初识分数降序
    while(r--)
    {
        split(); //先拆分 
        merge(); //后合并 
    } 
    cout << a[q];
     return 0;
}

 

posted @ 2023-08-16 21:48  CRt0729  阅读(39)  评论(0编辑  收藏  举报