划一波水,写一道题

洛谷 P1309 瑞士轮

  • 首先,这道题啊。。。好题!!!(什么破玩意,都是假象)

题目分析

  • 题目背景,没用,略;
  • 描述

\(2×N\)名编号为 \(1\sim2N\)的选手共进行R轮比赛。每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。
每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1名和第2名、第3名和第4名、……、第(2K-1)名和第2K名……、第(2N-1)名和第2N名,各进行一场比赛。每场比赛胜者得1分,负者得0分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。
现给定每个选手的初始分数及其实力值,试计算在R轮比赛过后,排名第Q的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。

是不是看到这道题非常兴奋:这不就是快排嘛?!

真的那么简单吗???

然鹅事实狠狠地又打了自己的脸(啪!)——它的复杂度非常非常非常非常……高!达到了惊银的$O(nlogn)$以上

so……超时了。那怎么办。。。没办法了?怎么可能!

仔细读题,模拟后可以知道,每轮比赛结束后,胜利者和失败者两个集合的内部顺序是不会被打乱的。所以也就是说这里每一轮比赛下来,有一半人的相对顺序已经确定了,二我们所熟知的快排`sort`是针对随机数列的,既然已经有确定的部分,那它那可怜的优势也没有了,也就不那么高效了。

这样看来我们就需要新的排序方法——归并(我太弱了,只能想到归并)

so,每一轮比赛后用O(N)的时间归并一次,时间就够了。

没了。没了?$\downarrow$

数据观察

  • 作为noip2011 J组的T3,你真的觉得他不会在数据上难为你?那你可太天真了

对于\(30\%\)的数据,\(1 ≤ N ≤ 100\)
对于\(50\%\)的数据,\(1 ≤ N ≤ 10,000\)
对于\(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\)

呵呵。。。看到空间没,别忘了开二倍!

而且,数据真的hin水。

代码实现

#include<cstdio>
using namespace std;
int b, c, n, r, q;
int s[200001];
bool ds(int x,int y)
{
    if(s[x]==s[y])//如果分数相等
    {
        return x<y;//x和y哪个大
    }
    return s[x]>s[y];//x和y的分数哪个大
}
int main()
{
    scanf("%d%d%d",&n,&r,&q);
    int a[2*n+1], x[n+1], y[n+1], w[2*n+1];
    n*=2;
    for(int i=1;i<=n;i++)
    {
        a[i]=i;//写好排名的数据
        scanf("%d",&s[i]);//初始分
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w[i]);//能力大小
    }
    sort(a+1,a+(n+1),ds);//第一次排序
    for(int i=1;i<=r;i++)
    {
        b=0;//b代表现在的局数
        for(int j=1;j<=n;j+=2)//每局
        {
            if(w[a[j]]>w[a[j+1]])
            {
                s[a[j]]++;
                x[++b]=a[j];//j赢
                y[b]=a[j+1];//j+1输
            }
            else//反过来
            {
                s[a[j+1]]++;
                x[++b]=a[j+1];
                y[b]=a[j];
            }
        }
        int l=1,j=1,k=1;//归并排序
        while(l<=b && j<=b)
        {
            if(ds(x[l],y[j]))//比较
            {
                a[k++]=x[l++];
            }
            else
            {
                a[k++]=y[j++];
            }
        }
        while(l<=b)//剩余的数
        {
            a[k++]=x[l++];
        }
        while(j<=b)//剩余的数
        {
            a[k++]=y[j++];
        }
    }
    printf("%d",a[q]);
    return 0;
}
posted @ 2020-03-04 23:04  orange_lyc  阅读(121)  评论(0编辑  收藏  举报