noip 瑞士轮 - 归并
背景
在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。
本题中介绍的瑞士轮赛制,因最早使用于 1895 年在瑞士举办的国际象棋比赛而得名。
它可以看作是淘汰赛与循环赛的折衷,既保证了比赛的稳定性,又能使赛程不至于过长。
描述
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,每两个数之间用一个空格隔开,其中 s 表示编号为 i 的选手的初始分数。
第三行是 2*N个正整数 w1, w2, …, w2N,每两个数之间用一个空格隔开,其中 w 表示编号为 i 的选手的实力值。
输出格式
输出只有一行,包含一个整数,即 R 轮比赛结束后,排名第 Q 的选手的编号。
样例1
样例输入1
2 4 2 7 6 6 7 10 5 20 15
样例输出1
1
限制
1s
提示
1 ≤ n ≤ 100,000
1 ≤ R ≤ 50
1 ≤ Q ≤ 2N
0 ≤ Si ≤ 10^8
1 ≤ Wi ≤ 10^8
来源
NOIP 2011 第三题
(转自https://vijos.org/p/1771)
首先一次快排,把胜方和败方分开。对胜方的得分每人加一,此时,对于存储胜方的数组来说,这个数组中的元素是有序的,对于存储败方的数组来说,元素也是有序,快排一次的复杂度是O(nlog2n),而归并的时间复杂度可以做到O(n),故这里使用归并(不是归并排序)。就可以AC了
Code:
1 /** 2 * codevs.cn & vijos.org 3 * Problem#1132 1771 4 * Accepted 5 * Time:609ms 637ms 6 * Memory:6636k 5260k 7 */ 8 #include<iostream> 9 #include<algorithm> 10 #include<cstring> 11 #include<cctype> 12 #include<cstdio> 13 using namespace std; 14 typedef bool boolean; 15 template<typename T> 16 inline void readInteger(T& u){ 17 char x; 18 while(!isdigit((x = getchar()))); 19 for(u = x - '0';isdigit((x = getchar()));u = (u << 3) + (u << 1) + x - '0'); 20 ungetc(x, stdin); 21 } 22 template<typename T> 23 void merger(T a[], T b[], T o[], int size){ 24 int l = 0,r = 0; 25 int t = 0; 26 while(l < size || r < size){ 27 if(r >= size || l < size && a[l] > b[r]){ 28 o[t++] = a[l++]; 29 }else{ 30 o[t++] = b[r++]; 31 } 32 } 33 } 34 typedef class Player{ 35 public: 36 int score; 37 int lvl; 38 int num; 39 Player(const int score = 0, const int lvl = 0, const int num = 0):score(score), lvl(lvl), num(num){} 40 boolean operator >(Player another) const{ 41 if(this->score != another.score) return this->score > another.score; 42 return this->num < another.num; 43 } 44 }Player; 45 boolean cmpare(const Player& a, const Player& b){ 46 return a > b; 47 } 48 int n; 49 int r,q; 50 Player *win, *lost, *list; 51 inline void init(){ 52 readInteger(n); 53 readInteger(r); 54 readInteger(q); 55 list = new Player[(const int)(2 * n + 1)]; 56 win = new Player[(const int)(n + 1)]; 57 lost = new Player[(const int)(n + 1)]; 58 for(int i = 0;i < (n << 1); i++){ 59 list[i].num = i + 1; 60 readInteger(list[i].score); 61 } 62 for(int i = 0;i < (n << 1); i++) 63 readInteger(list[i].lvl); 64 } 65 inline void alloc(){ 66 for(int i = 0; i < (n << 1); i += 2){ 67 if(list[i].lvl > list[i + 1].lvl){ 68 win[(i >> 1)] = list[i]; 69 lost[(i >> 1)] = list[i + 1]; 70 }else{ 71 win[(i >> 1)] = list[i + 1]; 72 lost[(i >> 1)] = list[i]; 73 } 74 win[(i >> 1)].score++; 75 } 76 } 77 inline void solve(){ 78 sort(list, list + (n << 1), cmpare); 79 for(int i = 1; i <= r; i++){ 80 alloc(); 81 merger(win, lost, list, n); 82 } 83 cout<<list[q - 1].num; 84 } 85 int main(){ 86 init(); 87 solve(); 88 return 0; 89 }