CF1175C Electrification [二分答案]

ElectrificationElectrification

题目描述见链接 .


color{red}{正解部分}

{ai}{a_i} 放到数轴中, 题意转化 为: 在数轴上选择一个点 xx , 使得与 xx 距离第 KK 大的点 到 xx 的距离 dd 最小 .
dd 显然是具有 单调性 的, 考虑 二分答案, 二分出 dd, 再考虑怎么检查 dd 是否合法,

[xd,x+d][x-d, x+d] 中的 点数 不超过 KK 个时, 说明 xx 合法,
但是直接枚举 xx 去检查 dd 是否合法显然会 TLETLE, 考虑更快的方法,

枚举 左端点 ala_l, 设 y=l+K1y = l+K-1, 右端点 ara_r,
aral2daral2da_r - a_l le 2d ightarrow frac{a_r-a_l}{2} le d , 说明 x=al+ar2x = lfloor frac{a_l+a_r}{2} floor 时, 距离 xxKK 近的点距离不超过 dd, 符合题目要求 .

于是就可以 O(n)O(n) checkcheck 了 .


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
", Ans);
}

int main(){
        int T = read();
        while(T --) Work();
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822453.html