题解【洛谷P1314】[NOIP2011]聪明的质监员

题面

题解

不难发现,\(W\)增大时,\(Y\)值会随之减小。

于是考虑二分\(W\)

如何\(\mathcal{O}(N)check?\)

每一次前缀和记录一下\(1…i\)之间\(w_i \ge W\)的个数及\(v_i\)之和。

计算出\(|Y_1+Y_2+…+Y_m-S|\),与当前的最小答案取最小值。

返回\(Y_1+Y_2+…+Y_m > S\)

代码

#include <bits/stdc++.h>
#define int long long
#define itn int
#define gI gi

using namespace std;

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

const int maxn = 200003;

int n, m, s, w[maxn], v[maxn], Y, l[maxn], r[maxn], maxx, sum, ans = 1000000000000007, qw[maxn], qv[maxn];

inline bool check(int x)
{
	memset(qw, 0, sizeof(qw));
	memset(qv, 0, sizeof(qv));//初始化
	for (int i = 1; i <= n; i+=1) qw[i] = qw[i - 1] + (w[i] >= x), qv[i] = qv[i - 1] + (w[i] >= x) * (v[i]);//前缀和
	Y = sum = 0;
	for (int i = 1; i <= m; i+=1)
	{
		Y += (qw[r[i]] - qw[l[i] - 1]) * (qv[r[i]] - qv[l[i] - 1]);//计算Y值的和
	}
	if (Y - s < 0) sum = s - Y;
	else sum = Y - s;
	return Y >= s;
}

signed main()
{
	n = gi(), m = gi(), s = gi();
	for (int i = 1; i <= n; i+=1)
	{
		w[i] = gi(), v[i] = gi();
		maxx = max(maxx, w[i]);
	}
	for (int i = 1; i <= m; i+=1)
	{
		l[i] = gi(), r[i] = gi();
	}
	int l = 0, r = maxx;
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (check(mid)) l = mid + 1;
		else r = mid - 1;
		ans = min(ans, sum);//更新答案
	}
	printf("%lld\n", ans);//输出
	return 0;
}
posted @ 2019-11-07 17:15  csxsi  阅读(116)  评论(0编辑  收藏  举报