原題連結:https://www.luogu.com.cn/problem/P1309
題意解讀:2n個人,每次按分數從大到小排名,相鄰兩人比賽,勝者得1分,r輪後,第q個人是誰。
解題思路:
如果直接使用模擬法,每輪比賽後都進行一次排序,總的時間複雜度是r*2n*log2n,大概在50*2*10^5*18 > 10^8,會超時,不過大概可以得到50分。
再進一步思考,每一次比賽前,已經按照分數大到小排好序,每一輪比賽,總會有n個勝利,n個人失敗,勝利的n個人都加1分,加1分後勝者的n個人相對排序不變,失敗的n個人相對排序也不變!
因此,容易想到,可以針對每輪比賽的勝者、敗者這兩個有序的序列進行歸併,合併成一個有序序列,而歸併的時間複雜度為O(n),總複雜度在r*O(n)。
100分程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, r, q;
struct node
{
int id; //編號
int s; //分數
int w; //實力值
};
node a[2 * N], b[N], c[N]; //b是每次比賽的勝者組,c是每次比賽的敗者組
bool cmp(node a, node b)
{
if(a.s == b.s) return a.id < b.id;
return a.s > b.s;
}
int main()
{
cin >> n >> r >> q;
for(int i = 1; i <= 2 * n; i++) cin >> a[i].s, a[i].id = i;
for(int i = 1; i <= 2 * n; i++) cin >> a[i].w;
sort(a + 1, a + 2 * n + 1, cmp); //按選手的分數從大到小排序
while(r--) //進行r輪比賽
{
int cnt = 0;
for(int i = 1; i <= 2 * n - 1; i+=2) //列舉每一對比賽選手
{
//對勝者進行加分,並將勝者加入勝者組,敗者加入敗者組
if(a[i].w > a[i+1].w) a[i].s++, b[++cnt] = a[i], c[cnt] = a[i+1];
else a[i+1].s++, b[++cnt] = a[i+1], c[cnt] = a[i];
}
//對勝者組、敗者組進行歸併
int i = 1, j = 1, k = 1;
while(i <= cnt && j <= cnt)
{
if(cmp(b[i], c[j])) a[k++] = b[i++];
else a[k++] = c[j++];
}
while(i <= cnt) a[k++] = b[i++];
while(j <= cnt) a[k++] = c[j++];
}
cout << a[q].id;
return 0;
}