Gym 101510C

题意略。

思路:

由于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;
}

 

转载于:https://www.cnblogs.com/tiberius/p/9301538.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值