Codeforce 1704 B. Luke is a Foodie
题意
大意就是给你正整数n,x;
然后给出n个正整数,a[1],a[2],a[3]…a[n];
对于每一个a[i] ( 1 ≤ i ≤ n) ,我们自己给出一个v , 使得
| v − a[i] | ≤ x
这个v最开始是我们自己确定的,我们需要确定一个合适的v,使得这个区间[ v - x , v + x ] 要尽可能多地囊括数个a[i];
这个v可以人为地变动,我们需要给出一个ans,ans是最小变动v的次数,使得这个区间[ v - x , v + x ] 囊括住所有的a;
思路
我们要先想明白一个事情,
对于a[1]和a[2],要怎么样子找一个v,使得区间[ v - x , v + x ],使得它囊括a[1]和a[2];
看图:
绿色部分是[a1 - x , a1 + x ];
蓝色部分是[a2 - x , a2 + x ];
它们重合的部分就是v可以取到的范围;
道理很简单:想象甲和乙的手臂是一样长的;
他们分别把手臂张开,然后两个人的手臂搭在一起;
此时来了一个丙,他的手臂跟甲乙一样长;
丙只要站在手臂重合区,就可以碰到甲和乙;
我们只要遍历a[i] 和 a[i+1],找出那个v存在的区间——上图中红色的部分,看看能不能它能不能囊括所有的a;
如果不行,更换一个新的区间,ans++,依次类推下去,直到所有的a都被遍历过一遍;
最后输出ans的值
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10;
int n,x;
int a[N];
void solve(){
cin>>n>>x;
for(int i = 0 ; i < n ; i ++){
cin>>a[i];
}
int ans = 0 ;
int left = a[0] - x ,right = a[0] + x;
//严格保证left < right
for(int i = 1 ; i < n ; i ++){
int tmpl = a[i] - x ,tmpr = a[i] + x;
if(right < tmpl || left > tmpr){
ans ++ ;
left = tmpl;
right = tmpr;
//完全没有重合的区间,取最新那个点作为新的判定区;
}else{
left = max(left ,tmpl);
right = min(right , tmpr);
//更新区间;
}
}
cout<<ans<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
}