题目链接:P1309 瑞士轮
程序说明:
卡了一个晚上,思路比较简单但是细节很多,有很多大坑!
每轮比赛结束后都需要对选手的成绩进行排序,这道题不能用STL的sort()或者手写快排进行排序,否则会超时(除非开o2优化)。看了题解之后才知道要用归并排序,于是手写归并结果还是超时。其实是没有掌握到归并的精髓。
这道题并不需要把归并排序的完整过程写出来(比如递归什么的…),否则和快排就一样了仍然会超时。需要额外开两个数组,每次比赛后,赢的人到x数组,输的人到y数组,这样的话仍然能保证x数组和y数组分别有序,因此只需要进行归并操作就可以了(即双指针)。
不开o2就能ac的代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
//注意数组大小是2 * n
const int N = 200010;
int n, r, q;
struct node {
int num; //序号
int score; //分数
int weight; //权值
} a[N], x[N], y[N];
bool cmp(node a, node b) {
if(a.score == b.score) return a.num < b.num;
return a.score > b.score;
}
//归并操作
void merge_sort() {
int i = 1, j = 1, k = 1;
while(i <= n && j <= n) {
if(x[i].score > y[j].score || x[i].score == y[j].score && x[i].num < y[j].num)
a[k++] = x[i++];
else a[k++] = y[j++];
}
while(i <= n) a[k++] = x[i++];
while(j <= n) a[k++] = y[j++];
}
int main() {
//freopen("D://a.txt", "r", stdin);
scanf("%d%d%d", &n, &r, &q);
for(int i = 1; i <= n * 2; i++) {
scanf("%d", &a[i].score);
a[i].num = i;
}
for(int i = 1; i <= n * 2; i++) {
scanf("%d", &a[i].weight);
}
sort(a + 1, a + n * 2 + 1, cmp);
for(int i = 1; i <= r; i++) {
int k = 1;
for(int j = 1; j <= n * 2 - 1; j += 2) { //注意j是奇数
if(a[j].weight < a[j + 1].weight) {
a[j + 1].score++;
x[k] = a[j + 1];
y[k] = a[j];
k++;
}
else {
a[j].score++;
x[k] = a[j];
y[k] = a[j + 1];
k++;
}
}
merge_sort();
}
printf("%d", a[q].num);
//fclose(stdin);
return 0;
}