Luogu P1314 聪明的质监员

思路

二分答案加前缀和,二分答案自然不难想,就是这个前缀和。。。

用sum_v和sum_w分别记录两组前缀和。记录方式如下

        for(register int i=1; i<=n; i++) {
                if(w[i] < mid) {
                        sum_v[i] = sum_v[i-1];
                        sum_w[i] = sum_w[i-1];
                }
                else {
                        sum_v[i] = sum_v[i-1] + v[i];
                        sum_w[i] = sum_w[i-1] + 1;
                }
        }

  

 

吐槽

我调了很久,知道为什么吗

因为输入l和r的时候输入的l和v,把v的值都改变了,硬是调颓废了半下午

 

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

typedef long long LL;
const int maxn = 2e5+3;
const LL INF = 999999999999999;

using namespace std;

LL n, m, s, sum_v[maxn], sum_w[maxn], Ans, ans = INF, sum;
LL w[maxn], v[maxn], mx = -1, mn = INF, l[maxn], r[maxn];

inline bool judge(int mid) {
	Ans = 0;
	memset(sum_v, 0, sizeof(sum_v));
	memset(sum_w, 0, sizeof(sum_w));
	for(register int i=1; i<=n; i++) {
		if(w[i] < mid) {
			sum_v[i] = sum_v[i-1];
			sum_w[i] = sum_w[i-1];
		}
		else {
			sum_v[i] = sum_v[i-1] + v[i];
			sum_w[i] = sum_w[i-1] + 1;
		}
	}
	for(register int i=1; i<=m; i++)
		Ans += (sum_v[r[i]]-sum_v[l[i]-1]) * (sum_w[r[i]]-sum_w[l[i]-1]);
	sum = llabs(s-Ans);
	if(Ans > s) return true;
	else return false;
}

int main() {
	scanf("%lld%lld%lld", &n, &m, &s);
	for(register int i=1; i<=n; i++) {
		scanf("%lld%lld", &w[i], &v[i]);
		mx = max(mx, w[i]);
		mn = min(w[i], mn);
	}
	for(register int i=1; i<=m; i++) {
		scanf("%lld%lld", &l[i], &r[i]);
	}
	int ll = mn-1, rr = mx+2, mid;
	while (ll <= rr) {
		mid = (ll + rr)>>1;
		if(judge(mid))
			ll = mid+1;
		else rr = mid-1;
		ans = min(ans, sum);
	}
	printf("%lld", ans);
}

  

  

posted @ 2018-07-20 19:52  Mystical-W  阅读(172)  评论(0编辑  收藏  举报