洛谷 p1309 瑞士轮

题意:有很多选手,选手一开始有编号,初始积分和能力值,编号按输入顺序决定,输入完成后按积分排名,积分相同编号小的在前

规定比R轮比赛,每轮比赛第一名与倒数第一比,第二名与倒数第二比,依次类推。能力值大的赢,赢的加一分,输的不加,每次比完一轮都要动态刷新排名。

 

一开始,每次比完一轮我都会重新排个序,后面超时了,后面看到个更好的解法

因为每次比完,所有的赢家之间的排名和所有的输家之间的排名是不会变的(因为如果一个赢家,它上一轮是输家,那么它即使这一轮赢了也不会比上一轮就是赢家且排他前面的赢家分数高,其它上一轮是输家这一轮是赢家的人也和它一样都只加了一分,相对位置不会改变,同理输家们也是一样)所以可以每次比拼结束后赢家加入赢家组,输家加入输家组,这样这两个组中已经组内有序了,接下来再归并这两个组就能得出排名,这样每次刷新排名所要的时间复杂度只有logn

ps.当时不知道优先队列,现在发现估计可以用优先队列做,每次比拼一次更新完分数后再入队列

#include<bits/stdc++.h>
using namespace std;

typedef struct pa{
  int num;
  int points;
  int ability;
}Pa;
Pa a[200500];

bool cmp(Pa a, Pa b){
  if(a.points == b.points)
    return a.num < b.num;
  return a.points > b.points;
}

int main(){
  int n, r, q;
  cin >> n >> r >> q;
  n = n*2;
  for(int i=0; i<n; i++){
    cin >> a[i].points;
    a[i].num = i;
  }
  for(int i=0; i<n; i++)
    cin >> a[i].ability;
  sort(a, a+n, cmp);

  vector<Pa> winners;
  vector<Pa> losers;
  while(r--){
    winners.clear();
    losers.clear();
    for(int i=0; i<n; i+=2){
      if(a[i].ability > a[i+1].ability){
        a[i].points++;
        winners.push_back(a[i]);
        losers.push_back(a[i+1]);
      }else{
        a[i+1].points++;
        winners.push_back(a[i+1]);
        losers.push_back(a[i]);
      }
    }
      merge(winners.begin(), winners.end(), losers.begin(), losers.end(), a, cmp);
  }
  cout << a[q-1].num+1 << endl;
  return 0;
}

 

posted @ 2019-07-26 23:24  zuo_ti_jia  阅读(125)  评论(0编辑  收藏  举报