最近准备面试刷题,写到一题发现了非常巧妙的解法,在这里记录一下。
题目
思路
我们可以对员工的能力值 A A A和能力值 B B B的差的绝对值非递减排序,这样,排序在后面的员工就决定了较差的能力是 A A A还是 B B B
举个例子
假设我们选出了两名员工
i
i
i和
j
j
j,有
i
<
j
i < j
i<j
假设
A
i
<
B
i
A_i < B_i
Ai<Bi
那么员工
j
j
j就有两种情况,
A
j
<
=
B
j
A_j <= B_j
Aj<=Bj 或者
A
j
>
B
j
A_j > B_j
Aj>Bj
这里分开讨论
1、
A
j
<
=
B
j
A_j <= B_j
Aj<=Bj,那毫无疑问,最终答案是
A
i
+
A
j
2
\frac{A_i+A_j}{2}
2Ai+Aj
2、
A
j
>
B
j
A_j > B_j
Aj>Bj,这种情况最终答案应该是
B
i
+
B
j
2
\frac{B_i+B_j}{2}
2Bi+Bj,因为
B
i
−
A
i
<
A
j
−
B
j
B_i-A_i < A_j-B_j
Bi−Ai<Aj−Bj 即
B
i
+
B
j
<
A
i
+
A
j
B_i+B_j < A_i+A_j
Bi+Bj<Ai+Aj(我们已经对一个员工能力值的差值排序过了)
若 A i > B i A_i > B_i Ai>Bi,则和上面同理。
那么,我们可以知道,在排序之后的两个能力值之和的最小值由靠后的员工决定,所以可以顺序遍历排序后的员工,记录之前所有员工的两个能力值的最大值,取当前员工能力值较小的和该能力值的历史最大值相加后取平均即可。
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
#pragma GCC optimize(3)
typedef long long ll;
#define INF 0x3f3f3f3f
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
#define iss ios::sync_with_stdio(false)
#define debug(x) cout << #x << ": " << x << endl;
inline ll read()
{
ll s = 0, w = 1;
char ch = getchar();
while (ch < 48 || ch > 57)
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= 48 && ch <= 57)
s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
pair<int,int> par[200005];
int main(){
int n = read();
for(int i = 0 ; i < n ; ++i){
par[i].first = read();
par[i].second = read();
}
sort(par,par+n,
[](pair<int,int> a,pair<int,int> b){
return abs(a.first - a.second) < abs(b.first - b.second);
}
);//按能力值绝对值排序
int ma = par[0].first,mb = par[0].second;//分别是能力值A和B的最大值
int maxi = 0;
for(int i = 1 ; i < n ; ++i){
int res;//res表示取当前员工,和之前一个员工,最大的min(A,B)的大小
if(par[i].first > par[i].second) res = par[i].second + mb;
else res = par[i].first + ma;
maxi = max(maxi,res);
ma = max(ma,par[i].first);
mb = max(mb,par[i].second);
}
printf("%.1f\n",maxi/2.0);
}