洛谷P1309 瑞士轮 题解
暴力
按照题意,直接调用 \(STL\) 里面的 \(sort\) 即可。
但尴尬的是,出题人有意的卡了下这个数据,最大运算量在 \(1.5\) 亿左右,只有 \(60\) 分这样(或者 \(50\) 分)。
当然,开了 \(O2\) 优化不谈(经典不讲武德)。
优化
我们注意到,整个序列在一开始排序过之后是有序的,每轮比赛之后,整体不会发生大的波动,并不需要对整个序列进行整体的大型排序,只需要微调一下就 \(OK\) 了。
方案一
以第 \(2*k-1\) 和 \(2*k\) 为第 \(k\) 组,可以注意到,第 \(k\) 组的胜者至多进入第 \(k-1\) 组,第 \(k\) 组的败者最多跌到第 \(k+1\) 组,那么理论上应该只要以 \(4\) 为单位,进行多次排序就可以了。
很可惜,调了一晚上都是 \(WA\) ,先挖个坑,等证明其错误或者找到其正确实现的方法之后再补上。
方案二
每一轮比赛完时候,胜者和败者分别有序,完美符合归并排序的性质,可以在 \(O(N)\) 内排序好,这样就可以把复杂度降下来了。
对了,顺便知道了原来 \(STL\) 里面有一个合并有序数组的函数 \(merge\) 。(奇怪的函数增加了!)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int n, R, Q;
struct node {
int x;
int score, ability;
bool operator < (const node rhs) {
if (score != rhs.score)return score > rhs.score;
return x < rhs.x;
}
};
node a[N], winner[N], loser[N];
int main()
{
//read
scanf("%d%d%d", &n, &R, &Q);
for (int i = 1; i <= 2*n ; ++i) {
a[i].x = i;
scanf("%d", &a[i].score);
}
for (int i = 1; i <= 2*n ; ++i)
scanf("%d", &a[i].ability);
//solve
sort(a + 1, a + 2*n + 1);
while (R--) {
//play
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= n; ++i) {
node &p = a[2*i-1], &q = a[2*i];
if (p.ability < q.ability)
q.score++, winner[i] = q, loser[i] = p;
else
p.score++, winner[i] = p, loser[i] = q;
}
//sort
merge(winner + 1, winner + n + 1,
loser + 1, loser + n + 1,
a + 1);
}
//print
printf("%d", a[Q].x);
return 0;
}