P1309 瑞士轮 排序选择 时间限制 归并排序

  

题目背景

在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。

本题中介绍的瑞士轮赛制,因最早使用于18951895年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折中,既保证了比赛的稳定性,又能使赛程不至于过长。

题目描述

2 imes N2×N 名编号为 1sim 2N12N 的选手共进行R 轮比赛。每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。

每轮比赛的对阵安排与该轮比赛开始前的排名有关:第11 名和第22 名、第 33 名和第 44名、……、第2K - 12K1名和第2K2K名、…… 、第2N - 12N1名和第2N2N名,各进行一场比赛。每场比赛胜者得11分,负者得 00分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。

现给定每个选手的初始分数及其实力值,试计算在R 轮比赛过后,排名第QQ 的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。

输入输出格式

输入格式:

第一行是三个正整数N,R ,QN,R,Q,每两个数之间用一个空格隔开,表示有 2 imes N2×N名选手、RR 轮比赛,以及我们关心的名次 QQ。

第二行是2 imes N2×N 个非负整数s_1, s_2, …, s_{2N}s1,s2,,s2N,每两个数之间用一个空格隔开,其中s_isi表示编号为ii 的选手的初始分数。 第三行是2 imes N2×N 个正整数w_1 , w_2 , …, w_{2N}w1,w2,,w2N,每两个数之间用一个空格隔开,其中 w_iwi 表示编号为ii 的选手的实力值。

输出格式:

一个整数,即RR 轮比赛结束后,排名第QQ 的选手的编号。

输入输出样例

输入样例#1: 复制
2 4 2 
7 6 6 7 
10 5 20 15 
输出样例#1: 复制
1

一看是一道超级水题
但是每轮进行排序会超时三个点
普通超时代码:
#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define inf 0x3f3f3f3f
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 500+5

struct node
{
    int id;
    int ab;
    int val;
}s[200000+5];

bool cmp(node a,node b)
{
    return a.val>b.val||a.val==b.val&&a.id<b.id;
}

int main()
{
    int n,m,k;RIII(n,m,k);
    rep(i,1,2*n)
    RI(s[i].val),s[i].id=i;
    rep(i,1,2*n)
    RI(s[i].ab);
    sort(s+1,s+1+2*n,cmp);
    while(m--)
    {
        rep(i,1,n)
        if(s[2*i].ab>s[2*i-1].ab )
            s[2*i].val++;
        else s[2*i-1].val++;
        sort(s+1,s+1+2*n,cmp);
    }
    cout<<s[k].id<<endl;
    return 0;
}
View Code

快速排序对随机数字具有很大优势  

但是这题的数据只是相邻的有变化  至少n个数据是已经有序的  用快排效率非常低

可以使用归并排序

c++函数库里面有个merge函数

将两个有序序列合并为一个有序序列  这其中就蕴含了归并排序的思想  

注意merge的格式!

#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define inf 0x3f3f3f3f
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 500+5
struct node
{
    int id,ab,val;
}s[200000+5],win[100000+5],lose[100000+5];
bool cmp(node a,node b)
{
    return a.val>b.val||a.val==b.val&&a.id<b.id;
}
int main()
{
    int n,m,k;RIII(n,m,k);
    rep(i,1,2*n)
    RI(s[i].val),s[i].id=i;
    rep(i,1,2*n)
    RI(s[i].ab);
    sort(s+1,s+1+2*n,cmp);
    while(m--)
    {
        int w=0,lo=0;
        
        rep(i,1,n)
        if(s[2*i].ab>s[2*i-1].ab )
        {
            s[2*i].val++;
            win[++w]=s[2*i];
            lose[++lo]=s[2*i-1];
        }
        else
        {
            s[2*i-1].val++;
            win[++w]=s[2*i-1];
            lose[++lo]=s[2*i];
        }
        
        merge(win+1,win+1+n,lose+1,lose+1+n,s+1,cmp);//注意格式
    }
    cout<<s[k].id<<endl;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/10661357.html