openjudge 瑞士轮

来源:互联网 发布:软件项目服务方案 编辑:程序博客网 时间:2024/04/27 23:08

4363:瑞士轮

  • 查看
  • 提交
  • 统计
  • 提问
总时间限制: 
1000ms 
内存限制: 
65535kB
描述

【背景】 
在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公
平,偶然性较低,但比赛过程往往十分冗长。 
本题中介绍的瑞士轮赛制,因最早使用于 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
提示
对于 30%的数据,1 ≤ N ≤ 100; 
对于 50%的数据,1 ≤ N ≤ 10,000; 

对于 100%的数据, 1 ≤ N ≤ 100,000, 1 ≤ R ≤ 50, 1 ≤ Q ≤ 2N, 0 ≤ s1, s2, …, s2N ≤ 108, 1 ≤ w1, w2, …, w2N ≤ 108

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct data
{
int score,power,num;
}; data a[1000003],a1[1000003];
int winner[100003],loser[100003];
int r,n,p,i,j;
int cmp(data x,data y)
{
    if (x.score<y.score||x.score==y.score&&x.num>y.num)
     return 0;
    return 1;
}
void merge()
{
int rr[200003];
int x=0,y=0;int start=0;
while(x<n&&y<n)
{
if (a[winner[x+1]].score>a[loser[y+1]].score||a[winner[x+1]].score==a[loser[y+1]].score&&a[winner[x+1]].num<a[loser[y+1]].num)
{
x++;
start++;
rr[start]=winner[x];
}
else
{
y++;
start++;
rr[start]=loser[y];
}
     }
    for (int l=x+1;l<=n;l++)
     {
      start++;
      rr[start]=winner[l];
     }
    for (int l=y+1;l<=n;l++)
     {
      start++;
        rr[start]=loser[l];
     }
for (int l=1;l<=2*n;l++)
a1[l]=a[l];
for (int l=1;l<=2*n;l++)
a[l]=a1[rr[l]];
}
int main()
{
scanf("%d%d%d",&n,&r,&p);
for (i=1;i<=2*n;i++)
 a[i].num=i;
for (i=1;i<=2*n;i++)
scanf("%d",&a[i].score);
for (i=1;i<=2*n;i++)
scanf("%d",&a[i].power);
    sort(a+1,a+2*n+1,cmp);
    for (i=1;i<=r;i++)
     {
      for (j=1;j<=n;j++)
       if (a[2*j-1].power>a[2*j].power)
        {
           a[2*j-1].score++;
           winner[j]=2*j-1;
           loser[j]=2*j;
        }
       else
        {
           a[2*j].score++;
           winner[j]=2*j;
           loser[j]=2*j-1;
  } 
merge();
     }
    cout<<a[p].num;
    return 0;
}//此题如果每次比赛后都进行sort排序,时间承受不了。因为我们发现每次比赛后胜利者与胜利者之间的相对位置是不变的,失败者也同样,所以可以用归并排序的思想每次把胜利者与失败者合并在一起,每次的时间复杂度差不多为O(N).

0 0