题目:
数轴上n个点。k个炸弹,每个炸弹可以将一个长2R+1的区间覆盖。问覆盖n个点的,R的最小值。
n≤50000,k≤10
做法:
很明显可以二分R的值。然后O(n)check。具体就是贪心地用区间的左端点覆盖当前最左边的点,这样每个区间都发挥最大的作用。然后看覆盖n个点需要用几个区间,设为cnt,若cnt>k,说明R小了,l = mid+1,否则r = mid-1。
代码:
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false), cin.tie(0) #define debug(a) cout << #a ": " << a << endl using namespace std; typedef long long ll; const int N = 5e4 + 7; int n, k, a[N]; bool judge(int R){ R <<= 1; int cnt = 0; for (int i = 1, j; i <= n; i = j){ for (j = i; j <= n && a[j]-a[i] <= R; ++j); cnt++; if (cnt > k) return false; } return true; } int main(void){ IOS; cin >> n >> k; for (int i = 1; i <= n; ++i) cin >> a[i]; sort(a+1, a+n+1); int l = 0, r = 1e9, ans; while (l <= r){ int mid = (l+r) >> 1; if (judge(mid)){ ans = mid; r = mid-1; }else{ l = mid+1; } } cout << ans << endl; return 0; }