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