P1314 聪明的质监员
题意:n个物品每个有一个重量w和价值v
然后给定m个区间
定义区间价值
$y=(\sum_j1)*(\sum_jv[j])\ \ \ \ w[j] \ge W,j \epsilon [l_i,r_i]$
找到一个W
使这些区间价值和-S的绝对值最小
输出最小值
思路:二分+前缀和
y无法直接相减,但是求y 的两部分可以直接相减
对于二分
如果当前价值和>S 说明限制可能有点小,导致满足的多,所以当前价值和大,因此我们要加大W限制,让其变小,才能让答案更小
同理,如果<S,就减小W的限制
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define int long long #define olinr return #define _ 0 #define love_nmr 0 #define DB double struct node { int fir; int sec; }sm[205050]; int n; int m; int s; int w[205050]; int v[205050]; int L[205050]; int R[205050]; int maxwight; int ans=0x7fffffffffffffff; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { x=-x; putchar('-'); } if(x>9) put(x/10); putchar(x%10+'0'); } inline int abss(int x) { if(x<0) return -x; return x; } inline void ok(int W,int &now) { for(int i=1;i<=n;i++) { sm[i].fir=sm[i-1].fir; sm[i].sec=sm[i-1].sec; if(w[i]>=W) { sm[i].fir++; sm[i].sec+=v[i]; } } for(int i=1;i<=m;i++) { now+=(sm[R[i]].fir-sm[L[i]-1].fir)*(sm[R[i]].sec-sm[L[i]-1].sec); } } signed main() { n=read(); m=read(); s=read(); for(int i=1;i<=n;i++) { w[i]=read(); v[i]=read(); maxwight=max(maxwight,w[i]); } for(int i=1;i<=m;i++) { L[i]=read(); R[i]=read(); } int l=0; int r=maxwight+1; int nowans=0; while(l<=r) { int mid=(l+r)>>1; nowans=0; ok(mid,nowans); ans=min(ans,abss(nowans-s)); if(nowans>s) l=mid+1; else if(nowans<s) r=mid-1; else { ans=0; break; } } put(ans); olinr ~~(0^_^0)+love_nmr; }
----olinr