试题描述

【背景】在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。本题中介绍的瑞士轮赛制,因最早使用于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表示编号为 i的选手的初始分数。第三行是2*N个正整数w1,w2,…,w2N,每两个数之间用一个空格隔开,其中wi表示编号为i的选手的实力值。
输出
输出只有一行,包含一个整数,即R轮比赛结束后,排名第Q的选手的编号。
输入示例
2 4 2
7 6 6 7
10 5 20 15
输出示例
1
其他说明
【数据范围】1≤N≤100,000,1≤R≤50,1≤Q≤2N,0≤s1,s2,…,s2N≤100000000,1≤w1,w2,…,w2N≤100000000。

一个SB题,我竟然WA了N发?!?!?!

每次得到有序的两个序列,合并即可。

宏定义不知道慢到哪里去了。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define lc ch[x][0]
#define rc ch[x][1]
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
struct Player {
int id,s,w;
bool operator < (const Player& ths) const {
if(s!=ths.s) return s<ths.s;
return id>ths.id;
}
}A[maxn],B[maxn];
int n,R,q;
int main() {
n=read()<<;R=read();q=read();
rep(,n) A[A[i].id=i].s=read();
rep(,n) A[i].w=read();
sort(A+,A+n+);reverse(A+,A+n+);
rep(,R) {
rep(,n>>) {
int a=(i<<)-,b=i<<;
if(A[a].w>A[b].w) A[a].s++;else A[b].s++;
if(A[a]<A[b]) swap(A[a],A[b]);
}
int l=,r=,t=;
rep(,n)
if((l<=n&&A[r]<A[l])||r>n) B[++t]=A[l],l+=;
else B[++t]=A[r],r+=;
rep(,n) A[i]=B[i];
}
printf("%d\n",A[q].id);
return ;
}
05-11 17:54