CF1175C Electrification [二分答案]

mac2022-06-30  112

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] [xd,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+K1, 右端点 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 aral2d2arald , 说明 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; }
最新回复(0)