P1309 瑞士轮---归并排序

题源:https://www.luogu.org/problem/P1309

题目背景

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

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

题目描述

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

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

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

输入格式

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

第二行是2 \times N2×N 个非负整数s_1, s_2, …, s_{2N}s1,s2,,s2N,每两个数之间用一个空格隔开,其中s_isi表示编号为ii 的选手的初始分数。 第三行是2 \times 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

说明/提示

【样例解释】

【数据范围】

对于30\%30%的数据,1 ≤ N ≤ 1001N100;

对于50\%50%的数据,1 ≤ N ≤ 10,0001N10,000;

对于100\%100%的数据,1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s_1, s_2, …, s_2n≤10^8,1 ≤w_1, w_2 , …, w_2n≤ 10^8

noip2011普及组第3题。

 

 

题意是什么呢<第一和第二比,赢的加1分,输的不变>

然后比r轮,然后每轮比完要排序,

可能又想每次计算完分数,然后快排

算下时间复杂度(r*n*logn),看下范围妥妥的超时

实际情况下更高,不信的可以算算

所以把每次获胜的放到一个数组,失败的放到另一个数组

然后两个指针分别对应两个数组,然后把较大的放到原数组替换即可

额,反正这是思路,具体的

c++的STL有超厉害的函数

merge---归并排序函数

具体怎么解释这个函数呢

函数参数:merge(first1,last1,first2,last2,result,compare);

firs1t为第一个容器的首迭代器,last1为第一个容器的末迭代器,first2为第二个容器的首迭代器,last2为容器的末迭代器,result为存放结果的容器,comapre为比较函数(可略写,默认为合并为一个升序序列)。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N= 2e5+7;
int n,r,q;
struct person
{
    int s, idx, w;

    // 运算符重载,双关键字排序
    bool operator<(const person &t)const
    {
        if (t.s != s)
            return s > t.s;
        return idx < t.idx;
    }
};
person p[N], loser[N], winer[N];

int main()
{


    cin >> n >> r >> q;
    for(int i = 1; i <= n*2; i++)
        cin >> p[i].s;
    for(int i = 1; i <= n*2; i++)
        cin >> p[i].w;
    for(int i = 1; i <= n*2; i++)
        p[i].idx = i;
    sort(p+1, p+1+n*2);

    for(; r--;) // 然后就是给双指针
    {
        for(int i=1; i<=n; i++)
        {
            if (p[2*i-1].w<p[2*i].w)
            {
                p[2*i].s++;
                loser[i]=p[2*i-1];
                winer[i]=p[2*i];
            }
            else
            {
                p[2*i-1].s++;
                loser[i]=p[2*i];
                winer[i]=p[2*i-1];
            }

        }
        merge(loser+1, loser+n+1, winer+1, winer+n+1, p+1);
    }
    cout << p[q].idx;
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/RE-TLE/p/11460849.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值