题目背景
在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。
本题中介绍的瑞士轮赛制,因最早使用于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,每两个数之间用一个空格隔开,其中si表示编号为ii 的选手的初始分数。 第三行是2×N 个正整数w1,w 2,…,w2N,每两个数之间用一个空格隔开,其中 wi表示编号为i 的选手的实力值。
输出格式
一个整数,即R 轮比赛结束后,排名第Q 的选手的编号。
输入输出样例
输入 #1
2 4 2
7 6 6 7
10 5 20 15
输出 #1
1
说明/提示
【样例解释】
【数据范围】
对于30%30%的数据,1≤N≤100;
对于50%50%的数据,1≤N≤10,000;
对于100%100%的数据,1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s_1, s_2, …, s_{2N}≤108,1 ≤w_1, w_2 , …, w_{2N}≤ 108。
noip2011普及组第3题。
思路
刚开始用的快排sort()一排到底,后来有四个点超时了,然后又换了stable_sort(),结果还是有三个点超时,最后不得不用归并排序,还好有merge()这种神器,不然就难受了。
源码
#include<bits/stdc++.h>
using namespace std;
class person
{
public:
long long int id, scare, num;
};
person s[200001], a[200001], b[200001];
bool cmp(person a, person b)
{
if(a.scare != b.scare)
return a.scare > b.scare;
return a.id < b.id;
}
int main()
{
int N, R, Q;
cin >> N >> R >> Q;
for (int i = 0; i < 2 * N; i++)
{
s[i].id = (long long int)i + 1;
cin >> s[i].scare;
}
for (int i = 0; i < 2 * N; i++)
cin >> s[i].num;
sort(s, s + 2 * N, cmp);
int t1;
for (int i = 0; i < R; i++)
{
t1 = 0;
for (int j = 0; j < 2 * N; j += 2)
{
if (s[j].num > s[j + 1].num)
{
a[t1].id = s[j].id;
a[t1].num = s[j].num;
a[t1].scare = s[j].scare + 1;
b[t1].id = s[j+1].id;
b[t1].num = s[j+1].num;
b[t1].scare = s[j+1].scare;
t1++;
}
else
{
a[t1].id = s[j+1].id;
a[t1].num = s[j+1].num;
a[t1].scare = s[j+1].scare + 1;
b[t1].id = s[j].id;
b[t1].num = s[j].num;
b[t1].scare = s[j].scare;
t1++;
}
}
merge(a, a + t1, b, b + t1, s, cmp);
}
cout << s[Q-1].id;
return 0;
}