题解:AT_abc424_e [ABC424E] Cut in Half
首先肯定不可能用模拟做,因为 k≤109k \le 10^9k≤109。
我们可以尝试二分长度为 xxx 的木棒,问题在于如何检查是否为 xxx。
我们可以尝试获取在最多只能切 kkk 次的情况下能获得多少根大于等于 xxx 的棍子。
然后就很好统计了,我们只需要在他大于等于的时候一直除二然后计数就行了。
那我们就计算长度大于等于 midmidmid 的木棒和长度大于等于 2×mid2 \times mid2×mid 的木棒,超过了 2×mid2 \times mid2×mid 的显然应该算两次(因为还可以切成两根更小的,这样能保证正确),然后再加上初始就大于等于 midmidmid 的木棒,这样就能精确的算出 midmidmid 的排名,然后根据排名调整 l,rl,rl,r 即可。
代码
#include <bits/stdc++.h>
using namespace std;
namespace hjyowl {
const int N = 1000010;
const long double eps = 1e-18;
long long a[N];
long long n, k, x;
long long checker(long double t) {long long s = 0;for (long long i = 1; i <= n; i++) {long long tt = a[i];if ((long double)tt + eps < t) {continue;}long long cc = 1;long double ccf = (long double)tt;long long u = 0;while (1) {u += cc;if (u >= k) {u = k;break;}if (ccf / 2.0 + eps < t) {break;}ccf /= 2.0;long long r = k - u;if (r <= 0) {break;}if (cc > r / 2) {cc = r;} else {cc <<= 1;}}s += u;if (s >= k) {return k;}}return s;
}
int main() {ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int T;cin >> T;while (T--) {cin >> n >> k >> x;long long mx = 0;for (long long i = 1; i <= n; i++) {cin >> a[i];if (a[i] > mx) {mx = a[i];}}long double l = 0, r = (long double)mx;for (int tm = 0; tm < 100; tm++) {long double m = (l + r) * 0.5;const long double eps = 1e-18;long long ss = 0;for (long long i = 1; i <= n; i++) {if ((long double)a[i] + eps >= m) {ss++;}}long long s1 = checker(m);long long s2 = checker(2.0 * m);long long f = ss + 2 * min(k, s2) - min(k, s1);if (f >= x) {l = m;} else {r = m;}}printf("%.15Lf\n", l);// cout << (long double)l << endl;}return 0;
}
} // namespace hjyowl
int main() { return hjyowl::main(); }