CodeForces 1837F Editorial for Two

洛谷传送门

CF 传送门

这是一个常规 \(\log^2\) 做法。

最大值最小,想到二分答案。

设二分一个 \(x\),枚举分割点,就相当于要求前缀和后缀选出若干个元素,使得和均 \(\le x\),并且选数的数量 \(\ge m\)

显然贪心选,也就是前缀和后缀都选最小的。设 \(f_i\)\([1, i]\) 的前缀,选出第 \([1, j]\) 小的数,和 \(\le x\)\(j\) 的最大值。这个随便树状数组上二分。同理设 \(g_i\) 表示 \([i, n]\) 的后缀的答案。最后判是否 \(\exists i \in [0, n], f_i + g_{i + 1} \ge m\) 即可。

时间复杂度 \(O(n \log n (\log n + \log V))\),其中 \(V\) 为值域。不知道为什么还要卡常才勉强能过。

code
// Problem: F. Editorial for Two
// Contest: Codeforces - Educational Codeforces Round 149 (Rated for Div. 2)
// URL: https://codeforces.com/group/bXwyZVR0kC/contest/1837/problem/F
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 300100;

ll n, m, a[maxn], b[maxn], p[maxn], c[maxn];
int f[maxn], g[maxn], d[maxn];

struct node {
	ll x, i;
} e[maxn];

bool cmp(node a, node b) {
	return a.x < b.x;
}

inline bool check(ll x) {
	for (int i = 0; i <= n + 1; ++i) {
		f[i] = g[i] = c[i] = d[i] = 0;
	}
	ll t = 0;
	for (int i = 1; i <= n; ++i) {
		t += a[i];
		for (int j = p[i]; j <= n; j += (j & (-j))) {
			c[j] += a[i];
			++d[j];
		}
		int k = 0;
		if (t <= x) {
			k = n;
			f[i] = i;
		} else {
			ll y = x;
			for (int j = 18; ~j; --j) {
				if (k + (1 << j) > n) {
					continue;
				}
				if (c[k + (1 << j)] <= y) {
					k += (1 << j);
					y -= c[k];
				}
			}
			for (int j = k; j; j -= (j & (-j))) {
				f[i] += d[j];
			}
		}
	}
	t = 0;
	for (int i = 0; i <= n + 1; ++i) {
		c[i] = d[i] = 0;
	}
	for (int i = n; i; --i) {
		t += a[i];
		for (int j = p[i]; j <= n; j += (j & (-j))) {
			c[j] += a[i];
			++d[j];
		}
		int k = 0;
		if (t <= x) {
			k = n;
			g[i] = n - i + 1;
		} else {
			ll y = x;
			for (int j = 18; ~j; --j) {
				if (k + (1 << j) > n) {
					continue;
				}
				if (c[k + (1 << j)] <= y) {
					k += (1 << j);
					y -= c[k];
				}
			}
			for (int j = k; j; j -= (j & (-j))) {
				g[i] += d[j];
			}
		}
	}
	for (int i = 0; i <= n; ++i) {
		if (f[i] + g[i + 1] >= m) {
			return 1;
		}
	}
	return 0;
}

void solve() {
	scanf("%lld%lld", &n, &m);
	ll s = 0;
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
		s += a[i];
		e[i].x = a[i];
		e[i].i = i;
	}
	sort(e + 1, e + n + 1, cmp);
	for (int i = 1; i <= n; ++i) {
		p[e[i].i] = i;
	}
	ll l = 0, r = s, ans = -1;
	while (l <= r) {
		ll mid = (l + r) >> 1;
		if (check(mid)) {
			ans = mid;
			r = mid - 1;
		} else {
			l = mid + 1;
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2023-05-26 15:30  zltzlt  阅读(58)  评论(0编辑  收藏  举报