试题描述 |
【背景】在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。本题中介绍的瑞士轮赛制,因最早使用于1895年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折衷,既保证了比赛的稳定性,又能使赛程不至于过长。 |
输入 |
输入的第一行是三个正整数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 ;
}