题解-luogu-p1314聪明的质监员

题目链接

咕咕咕

本题难度不大,第一眼就能看出需要用二分答案或倍增答案解决。

需要解决的第一个问题是如何根据一个猜测的参数 $W$ ,快速计算出检验结果 $Y$ 。由于只有 $w_j \ge W$ 的矿石才会对检验结果做出贡献,因此我们可以将 $w_j < W$ 的矿石忽略并预处理前缀和,并且回答 $M$ 个询问即可。

接下来应该考虑如何计算猜测值 $W$ 。观察到 $Y(W)$ 是单调不增的,我们可以用倍增求出满足 $Y \ge S$ 的最大 $W$ 值,那么满足 $Y<S$ 的最小 $W$ 值一定为 $W+1$ 。

最终答案即为 $\min\lbrace |Y(W)-S|,|Y(W+1)-S|\rbrace$ 。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N, M, ans = 1; ll S;
int w[200005], v[200005], l[200005], r[200005]; ll s1[200005], s2[200005];
inline ll Y(int W) {
for (register int i = 1; i <= N; ++i)
s1[i] = w[i] >= W ? s1[i - 1] + 1 : s1[i - 1],
s2[i] = w[i] >= W ? s2[i - 1] + v[i] : s2[i - 1];
ll ret = 0;
for (register int i = 1; i <= M; ++i)
ret += (s1[r[i]] - s1[l[i] - 1]) * (s2[r[i]] - s2[l[i] - 1]);
return ret;
}
int main() {
scanf("%d%d%lld", &N, &M, &S);
for (register int i = 1; i <= N; ++i) scanf("%d%d", &w[i], &v[i]);
for (register int i = 1; i <= M; ++i) scanf("%d%d", &l[i], &r[i]);
for (register int i = 17; i >= 0; --i)
ans += Y(ans + (1 << i)) >= S ? (1 << i) : 0;
printf("%lld", min(Y(ans) - S, S - Y(ans + 1)));
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×