[NOIP2011 普及组] 瑞士轮

题目

在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。

本题中介绍的瑞士轮赛制,因最早使用于1895年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折中,既保证了比赛的稳定性,又能使赛程不至于过长。

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

每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1 名和第2 名、第 3 名和第 4名、……、第2K1名和第2K名、…… 、第2N1名和第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 的选手的编号。

输入输出样例

输入 #1

2 4 2 

7 6 6 7 

10 5 20 15 

输出 #1

1

代码:

排序一下,模拟题意即可

觉得归并太长又容易出错,可此题用归并比sort快,有些无奈。

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 #define N 200100
 5 int n,r,q;
 6 int num[N],win[N],lose[N];
 7 int s[N],w[N];
 8 bool cmp(int x,int y)
 9 { 10 return s[x]==s[y]?x<y:s[x]>s[y]; 11 } 12 void merge() 13 { 14 int i,j; 15 i=j=1,num[0]=0; 16 while(i<=win[0] && j<=lose[0]){ 17 if(cmp(win[i],lose[j])) 18 num[++num[0]]=win[i++]; 19 else 20 num[++num[0]]=lose[j++]; 21  } 22 while(i<=win[0]) num[++num[0]]=win[i++]; 23 while(j<=lose[0]) num[++num[0]]=lose[j++]; 24 } 25 int main() 26 { 27 cin>>n>>r>>q; 28 n*=2; 29 for(int i=1; i<=n; i++){ 30 num[i]=i; 31  } 32 for(int i=1; i<=n; i++){ 33 cin>>s[i]; 34  } 35 for(int i=1; i<=n; i++){ 36 cin>>w[i]; 37  } 38 sort(num+1,num+n+1,cmp); 39 for(int i=1; i<=r; i++) { 40 win[0]=lose[0]=0; 41 for(int j=1; j<=n; j+=2) 42 if(w[num[j]]>w[num[j+1]]) { 43 s[num[j]]++; 44 win[++win[0]]=num[j]; 45 lose[++lose[0]]=num[j+1]; 46 } else { 47 s[num[j+1]]++; 48 win[++win[0]]=num[j+1]; 49 lose[++lose[0]]=num[j]; 50  } 51  merge(); 52  } 53 cout<<num[q]; 54 return 0; 55 }

猜你喜欢

转载自www.cnblogs.com/FedLx/p/11515414.html