牛客编程巅峰赛S1第5场 - 青铜&白银 C - 排对(归并排序求逆序对)
思路:优先队列求出每个人的最短用时,归并排序求最短用时的逆序对
归并排序将两段区间 [l, mid] 和 [mid + 1, r] 合并时,如左区间中 a[i] > a[j],a[j]与 a[i] ~ a[mid] 都构成逆序对,ans += mid - i + 1;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll b[100010], t[100010];
class Solution {
public:
ll ans = 0;
void _merge(int l, int mid, int r) ///合并
{
int p = l, q = mid + 1;
for(int i = l; i <= r; ++i)
{
if(p <= mid && (q > r || t[p] <= t[q]))
{
b[i] = t[p];
p++;
}
else
{
b[i] = t[q];
q++;
ans += mid - p + 1;
}
}
for(int i = l; i <= r; ++i)
t[i] = b[i];
return ;
}
void mergesort(int l, int r)
{
if(l >= r) return;
int mid = (l + r) / 2;
mergesort(l, mid);
mergesort(mid + 1, r);
_merge(l, mid, r);
}
long long getNumValidPairs(int n, int m, vector<int>& a) {
ans = 0;
priority_queue<long long, vector<long long>, greater<long long> >q;
for(int i = 0; i < min(n, m); ++i)
{
t[i] = 1ll * a[i];
q.push(t[i]);
}
for(int i = m; i < n; ++i)
{
ll tp = q.top();
q.pop();
t[i] = tp + 1ll * a[i];
q.push(t[i]);
}
mergesort(0, n - 1);
return ans;
}
};