温和的提比略 阅读(5) 评论(0)

题意略。

思路:

由于xi的选取是任意的,所以我们不用去理会题目中的xi数列条件。主要是把关注点放在长度为L的线段覆盖至少k个整数这个条件上。

像这种取到最小的合法解的问题,我们应该要想到使用二分法来试探。

那么在验证时,如果我们要验证下标为i的的这个项是否能被一个包含k个元素的区间覆盖,就要枚举这个区间左边端点 <= i 并且 右边端点 >= i的所有情况,

在这些情况中,只要存在一个合法的解,那么该项就可以找到一个合法的xi。

如果我们对于每一个项都这么验证,那么我们的时间复杂度无法承受。

我们发现,如果当前区间已经包含了 i 和 i + 1 ,那么如果对于i来说,这个区间的r - l + 1 <= L,那么对于i + 1来说,该区间也是合法的。

也就是说,我们可以利用上前面的结果,当需要的时候,我们才去移动这个验证区间。

如果当前区间的长度大于L,那么我们也需要右移这个区间,直到找到一个合法的区间,如果在包含 i 的前提下,该区间不存在,

那么说明这个L不行。

详见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 200005;

LL store[maxn],minn,maxx;
int n,k;

bool jud(LL x)
{
      int l,r;
      bool ret = true;
      l = 0,r = k - 1;
      for (int i = 0;i < n;++i)
      {
        while ((store[r] - store[l] > x && l < i && r < n - 1) || r < i){
            ++l,++r;
        }
           if (store[r] - store[l] > x)
           {
            ret = false;
              break;
        }
      }
      return ret; 
}

int main(){
    scanf("%d%d",&n,&k);
    scanf("%lld",&store[0]);
    minn = maxx = store[0];
    for(int i = 1;i < n;++i){
        scanf("%lld",&store[i]);
        minn = min(minn,store[i]);
        maxx = max(maxx,store[i]);
    }
    sort(store,store + n);
    LL l = 0,r = maxx - minn;
    while(l < r){
        LL mid = (l + r)>>1;
        if(jud(mid)) r = mid;
        else l = mid + 1;
        //printf("mid == %lld\n",mid);
    }
    printf("%lld\n",l);
    return 0;
}