在一个非降序列中,查找与给定值最接近的元素。
第一行包含一个整数 n n n,为非降序列长度。 1 ≤ n ≤ 100000 1 \leq n \leq 100000 1≤n≤100000。
第二行包含n个整数,为非降序列各元素。所有元素的大小均在 0 0 0 ~ 1 , 000 , 000 , 000 1,000,000,000 1,000,000,000之间。
第三行包含一个整数m,为要询问的给定值个数。 1 ≤ m ≤ 10000 1\leq m \leq 10000 1≤m≤10000。
接下来m行,每行一个整数,为要询问最接近元素的给定值。所有给定值的大小均在 0 0 0 ~ 1 , 000 , 000 , 000 1,000,000,000 1,000,000,000之间。
m m m行,每行一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。
假设输入的序列为 a a a 对于每一个 a i a_i ai,我们求出它与查找的元素的差,因为 a a a肯定是单调递增的,所以其实每个 a i a_i ai与查找元素的差一定是一个凹函数 以1 3 4 5 8 9,查找元素为6为例,以 i i i为 x x x轴,每个 a i a_i ai与查找元素的差为 y y y轴建立直角坐标系,画出函数:
根据函数可以很容易的知道,我们的答案就在 a 4 a_4 a4处,这时差最小为 1 1 1
那么最终我们的题目就转化为求一个凹函数的最小值,一个三分解决!
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> using namespace std; const int MAXN=100005; long long a[MAXN]; long long b[MAXN]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int m; scanf("%d",&m); long long q; while(m--){ scanf("%lld",&q); int l=1,r=n; while(l<r){ int midl=l+(r-l)/3; int midr=r-(r-l)/3; if(abs(q-a[midl])>abs(q-a[midr])){ l=midl+1; } else{ r=midr-1; } } int d1=abs(a[l]-q); int d2=abs(a[r]-q); if(d1<d2){ printf("%lld\n",a[l]); } else{ printf("%lld\n",a[r]); } } return 0; }