题目描述
在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。
本题中介绍的瑞士轮赛制,因最早使用于1895年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折衷,既保证了比赛的稳定性,又能使赛程不至于过长。
2×N名编号为1至2×N的选手共进行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的选手的实力值。
输出格式
一行,包含一个整数,即R轮比赛结束后,排名第Q的选手的编号。
输入样例
2 4 2
7 6 6 7
10 5 20 15
输出样例
1
题解
我们每进行一轮,就将胜者和败者分别放在两个数组里,用归并排序的并思想合并这两个数组,这样就不会TLE了。
#include <iostream> #include <cstdio> #define MAX_N 100000 using namespace std; int n, r, q; struct Node { int idx; int s, w; }a[MAX_N << 1 | 1], b[MAX_N << 1 | 1]; void Merge(); void Merge_Sort(int, int); int Read(); int main() { n = Read(); r = Read(); q = Read(); n <<= 1; for(register int i = 1; i <= n; ++i) { a[i].s = Read(); a[i].idx = i; } for(register int i = 1; i <= n; ++i) { a[i].w = Read(); } Merge_Sort(1, n); while(r--) { for(register int i = 1, j = 1, k = (n >> 1) + 1; i < n; i += 2, ++j, ++k) { if(a[i].w > a[i + 1].w) ++a[i].s, b[j] = a[i], b[k] = a[i + 1]; else ++a[i + 1].s, b[j] = a[i + 1], b[k] = a[i]; } Merge(); } printf("%d", a[q].idx); return 0; } void Merge_Sort(int lt, int rt) { if(lt == rt) return; int mid = lt + rt >> 1; Merge_Sort(lt, mid); Merge_Sort(mid + 1, rt); int i = lt, j = mid + 1, cnt = 0; if(a[mid].s > a[j].s) return; while(i <= mid && j <= rt) { if(a[i].s > a[j].s) b[++cnt] = a[i++]; else if(a[i].s == a[j].s && a[i].idx < a[j].idx) b[++cnt] = a[i++]; else b[++cnt] = a[j++]; } while(i <= mid) { b[++cnt] = a[i++]; } while(j <= rt) { b[++cnt] = a[j++]; } while(cnt) { a[lt + cnt - 1] = b[cnt]; --cnt; } return; } inline void Merge() { int mid = n >> 1; int i = 1, j = mid + 1, cnt = 0; while(i <= mid && j <= n) { if(b[i].s > b[j].s) a[++cnt] = b[i++]; else if(b[i].s == b[j].s && b[i].idx < b[j].idx) a[++cnt] = b[i++]; else a[++cnt] = b[j++]; } while(i <= mid) { a[++cnt] = b[i++]; } while(j <= n) { a[++cnt] = b[j++]; } return; } inline int Read() { int a = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') a = a * 10 + c - '0', c = getchar(); return a; }