洛谷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;
} 
posted @ 2020-12-23 00:05  cyhforlight  阅读(81)  评论(0编辑  收藏  举报