P1309 [NOIP2011 普及组] 瑞士轮

尝试了几次,复杂度为(O(R(nlogn + n))),分别用了每轮快排和归并排,极限时间约为(50 * 200000 * 17),时间限制0.5s,TLE。

思路:首先按照题目要求把运动员序列a排序,让他们按照(1 vs. 2, 3 vs. 4...)的方式比下去然后发现每一轮下来整个序列中赢的人的顺序仍然保持降序,输的人也保持降序,所以可以每一轮把赢的人和输的人分别放到两个序列中,然后再将它们降序合并到a里,这样的话,a仍然是降序的,复杂度为(O(n)),整体复杂度为(O(2 * Rn))

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;

struct node{
    int id, s, w;
    
    bool operator <(const node &n) const{
        if(s != n.s) return s > n.s;
        return id < n.id;
    }
}a[N << 1];

int n, m, q;

int main(){
    cin >> n >> m >> q;
    
    n = n << 1;
    for(int i = 1; i <= n; i ++) cin >> a[i].s;
    for(int i = 1; i <= n; i ++) cin >> a[i].w;
    for(int i = 1; i <= n; i ++) a[i].id = i;
    sort(a + 1, a + 1 + n);
 
    while(m --){
        vector<node> win, lose;
        for(int i = 1; i < n; i += 2)
            if(a[i].w > a[i + 1].w){ 
                a[i].s ++;
                win.push_back(a[i]);
                lose.push_back(a[i + 1]);
            }else{
                a[i + 1].s ++;
                win.push_back(a[i + 1]);
                lose.push_back(a[i]);
            }
        int i = 0, j = 0, k = 0;
        while(i < win.size() && j < lose.size()){
            if(win[i] < lose[j]) a[++ k] = win[i ++];
            else a[++ k] = lose[j ++];
        }
        while(i < win.size()) a[++ k] = win[i ++];
        while(j < lose.size()) a[++ k] = lose[j ++];
    }
    
    cout << a[q].id << endl;
    
    return 0;
}
原文地址:https://www.cnblogs.com/tomori/p/15238874.html