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); }
作者:Mystical-W
来源:http://www.cnblogs.com/bljfy
说明:客官~~您如果觉得写得好的话,记得给我点赞哦。如果要转载的请在合适的地方注明出处。谢
谢您的合作。您要是有什么有疑问的地方可以在下面给我评论。也可以直接私信我哦
声明:本作品由Mystical-W采用知识共享署名-非商业性使用-禁止演绎 4.0 国
际许可协议进行许可
来源:http://www.cnblogs.com/bljfy
说明:客官~~您如果觉得写得好的话,记得给我点赞哦。如果要转载的请在合适的地方注明出处。谢
谢您的合作。您要是有什么有疑问的地方可以在下面给我评论。也可以直接私信我哦
声明:本作品由Mystical-W采用知识共享署名-非商业性使用-禁止演绎 4.0 国
际许可协议进行许可