noip 瑞士轮 ————归并排序解法
背景
在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。
本题中介绍的瑞士轮赛制,因最早使用于 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,每两个数之间用一个空格隔开,其中 s 表示编号为 i 的选手的初始分数。
第三行是 2*N个正整数 w1, w2, …, w2N,每两个数之间用一个空格隔开,其中 w 表示编号为 i 的选手的实力值。
输出格式
输出只有一行,包含一个整数,即 R 轮比赛结束后,排名第 Q 的选手的编号。
样例1
样例输入1
2 4 2
7 6 6 7
10 5 20 15
样例输出1
1
限制
1s
提示
1 ≤ n ≤ 100,000
1 ≤ R ≤ 50
1 ≤ Q ≤ 2N
0 ≤ Si ≤ 10^8
1 ≤ Wi ≤ 10^8
来源
NOIP 2011 第三题
——————————————————————————————
以前没学过归并排序所以惠来学了一波
很容易想到每次赛前拍一波序让后直接比较
但是这样的复杂度是 r(n(logn+1))
很明显会T
但是我们可以发现一次比赛之后胜方之间的相对大小不变 败方也一样
所以很容易想到归并排序的思想所以复杂度就降成 rn 了
贴一波代码233333
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=250007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,r,q; int c1[M],c2[M],c[M],cnt,cnt1,cnt2,f[M]; struct node{int s,h,pos;}e[M],e1[M]; bool cmp(node a,node b){return a.s!=b.s?a.s>b.s:a.pos<b.pos;} void merge(){ int l=1,r=1; cnt=0; while(l<=m&&r<=m){ if(e[c1[l]].s<e[c2[r]].s) c[++cnt]=c2[r++]; else if(e[c1[l]].s>e[c2[r]].s) c[++cnt]=c1[l++]; else{ if(e[c1[l]].pos<e[c2[r]].pos) c[++cnt]=c1[l++]; else c[++cnt]=c2[r++]; } } while(l<=m) c[++cnt]=c1[l++]; while(r<=m) c[++cnt]=c2[r++]; for(int i=1;i<=n;i++) e1[i].s=e[c[i]].s,e1[i].h=e[c[i]].h,e1[i].pos=e[c[i]].pos; for(int i=1;i<=n;i++) e[i].s=e1[i].s,e[i].h=e1[i].h,e[i].pos=e1[i].pos; } int main() { m=read(); n=m<<1; r=read(); q=read(); for(int i=1;i<=n;i++) e[i].s=read(); for(int i=1;i<=n;i++) e[i].h=read(),e[i].pos=i; sort(e+1,e+1+n,cmp); //for(int i=1;i<=n;i++) printf("[%d %d %d]\n",e[i].s,e[i].h,e[i].pos);printf("\n"); for(int i=1;i<=r;i++){ cnt1=0; cnt2=0; for(int j=1;j<=n;j+=2) if(e[j].h<e[j+1].h) c1[++cnt1]=j,c2[++cnt2]=j+1; else c1[++cnt1]=j+1,c2[++cnt2]=j; for(int j=1;j<=m;j++) e[c2[j]].s++; merge(); //for(int j=1;j<=n;j++) printf("[%d %d %d]\n",e[j].s,e[j].h,e[j].pos);printf("\n"); } printf("%d\n",e[q].pos); return 0; }