题意

数轴上有 $k$ 个点是草地,每个草地有不同收益, $m$ 个点是地方的点,现在你要放置 $n$ 个我方的点,不能和敌方的点重合。

如果一个草地离最近的我方的点距离严格小于最近的敌方点距离,那么这个草地被占领。

给出敌方点和草地坐标(保证两两不同),求占领草地的最大收益和 。

$1\leq n,m,k\leq 2\times10^5,1\leq x\leq 10^9$

题解

考虑两两敌方点间的草地。之间最多放两个点就可以把草地全部收入囊中,1 个点就要考虑双指针扫最大价值。因为两点的价值一定小于等于一点的两倍,于是可以贪心,堆维护,每次取出的如果是一点的,就把两点塞进去,做 $n$ 次。

代码

const int N = 2e5 + 5;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	#define mp make_pair
	struct node {
		ll p, t;
	} a[N];
	ll n, m, k, ans, s[N], f[N], w[N], v[N];
	priority_queue<pair<ll, ll> > q;
	
	int main() {
		k = Read(), m = Read(), n = Read();
		for (int i = 1; i <= k; i++) a[i].p = Read(), a[i].t = Read();
		for (int i = 1; i <= m; i++) f[i] = Read();
		sort(a + 1, a + 1 + k, [](node x, node y) { return x.p < y.p; });
		sort(f + 1, f + 1 + m);
		f[0] = -1e9, f[m + 1] = 2e9;
		ll now = 1, l = 1, lst = 0, maxs = 0;
		for(int i = 1; i <= k; i++) {
			s[i] = s[i - 1] + a[i].t;
			while(l <= m && f[l] < a[i].p) {
				w[l] = maxs;
				v[l] = s[i - 1] - s[lst];
				lst = i - 1;
				now = i;
				maxs = 0;
				l++;
			}
			ll L = f[l - 1], R = f[l];
			while((a[i].p - a[now].p) * 2 >= R - L) now++;
			maxs = max(maxs, s[i] - s[now - 1]);
		}
		w[l] = maxs;
		v[l] = s[n] - s[lst];
		for (int i = 0; i <= k + 1; i++)
			q.push(mp(w[i], i));
		for (int i = 1; i <= n; i++) {
			pair<ll, ll> w = q.top();
			ans += w.first;
			q.pop();
			if(w.second) q.push(mp(v[w.second] - w.first, 0));
		}
		printf("%lld\n", ans);
		return 0;
	}
}

int main () {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2023-11-17 10:36:43