NOIP 2011 聰明的質檢員-二分答案
阿新 • • 發佈:2018-11-08
先解釋一下這個式子:
就是說如果區間[Li, Ri] 中 wj>=w的個數 乘以 所有的wj>=w的價值的和。
那麼我們可以二分w的值,通過Y與S的值來調整w,
具體來講,只要當下的Y大於S,那麼增加Mid(增大Mid質量),否則減小Mid。
至於check,我們可以O(n)的預處理字首和 and 字首積。總複雜度 O(nlogn)。
程式碼可能有些傻,好像是Debug的時候一頓亂改搞的。。。
#include <bits/stdc++.h> #define ll long long using namespace std; inline int gi () {int x=0, w=0; char ch=0; while (! (ch>='0' && ch<='9') ) { if (ch=='-') w=1; ch=getchar (); } while (ch>='0' && ch<='9') { x= (x<<3) + (x<<1) + (ch^48); ch=getchar (); } return w?-x:x; } const int Size=300010; int n,m,l=2147483647,r,Mid,PreNum[Size]; ll S,PreJ[Size],Ans,Minx=999999999999999; struct Stone { int wi, val; }s[Size]; struct Area { int l, r; }a[Size]; int main () { n=gi (), m=gi (); cin >> S; for (int i=1;i<=n;++i) { s[i].wi=gi (), s[i].val=gi (); l=min (l, s[i].wi); r=max (r, s[i].wi); } for (int i=1;i<=m;++i) { a[i].l=gi () ,a[i].r=gi (); } l--; r++; while (l<r) { Ans=0; Mid= (l+r) >> 1; for (int i=1;i<=n;++i) if (s[i].wi>=Mid) { PreNum[i]=PreNum[i-1]+1; PreJ[i]=PreJ[i-1]+s[i].val; } else { PreNum[i]=PreNum[i-1]; PreJ[i]=PreJ[i-1]; } for (int i=1;i<=m;++i) Ans+= (PreNum[a[i].r]-PreNum[a[i].l-1]) * (PreJ[a[i].r]-PreJ[a[i].l-1]); if (Ans>S) l=Mid+1; else r=Mid; Minx=min (Minx, llabs (Ans-S) ); } printf ("%lld\n", Minx); return 0; }