E l e c t r i f i c a t i o n Electrification Electrification
题目描述见链接 .
正 解 部 分 \color{red}{正解部分} 正解部分
将
{
a
i
}
\{a_i\}
{ai} 放到数轴中, 题意转化 为: 在数轴上选择一个点
x
x
x , 使得与
x
x
x 距离第
K
K
K 大的点 到
x
x
x 的距离
d
d
d 最小 .
d
d
d 显然是具有 单调性 的, 考虑 二分答案, 二分出
d
d
d, 再考虑怎么检查
d
d
d 是否合法,
当
[
x
−
d
,
x
+
d
]
[x-d, x+d]
[x−d,x+d] 中的 点数 不超过
K
K
K 个时, 说明
x
x
x 合法,
但是直接枚举
x
x
x 去检查
d
d
d 是否合法显然会
T
L
E
TLE
TLE, 考虑更快的方法,
枚举 左端点
a
l
a_l
al, 设
y
=
l
+
K
−
1
y = l+K-1
y=l+K−1, 右端点
a
r
a_r
ar,
若
a
r
−
a
l
≤
2
d
→
a
r
−
a
l
2
≤
d
a_r - a_l \le 2d \rightarrow \frac{a_r-a_l}{2} \le d
ar−al≤2d→2ar−al≤d , 说明
x
=
⌊
a
l
+
a
r
2
⌋
x = \lfloor \frac{a_l+a_r}{2} \rfloor
x=⌊2al+ar⌋ 时, 距离
x
x
x 第
K
K
K 近的点距离不超过
d
d
d, 符合题目要求 .
于是就可以 O ( n ) O(n) O(n) c h e c k check check 了 .
实 现 部 分 \color{red}{实现部分} 实现部分
#include<bits/stdc++.h>
#define reg register
const int maxn = 2e5 + 10;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
int N;
int K;
int Ans;
int A[maxn];
bool check(int x){
for(reg int i = 1; i+K-1 <= N; i ++){
int j = i + K - 1;
if(A[j]-A[i] <= (x << 1)){ Ans = A[i]+A[j] >> 1; return true; }
}
return false;
}
void Work(){
N = read(), K = read() + 1;
for(reg int i = 1; i <= N; i ++) A[i] = read();
int l = 0, r = A[N] - A[1];
while(l <= r){
int mid = l+r >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
printf("%d\n", Ans);
}
int main(){
int T = read();
while(T --) Work();
return 0;
}