[NOIP2011]聪明的质监员 题解
题目大意:
额……貌似蛮清晰的,就不赘述了。
思路:
首先不难发现M越大Y越小,因此可以二分答案(方向不要弄错),二分出最小的不小于S的Y即可。而计算Y时可用前缀和O(n+m)求得。两种边界情况也要考虑一下(同时long long不要少开)。
代码:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 #define ll long long 5 const int M=200008; 6 int n,m,i,h,t,k,mn,mx,mid,w[M],v[M],l[M],r[M]; 7 ll s,sum[M],num[M]; 8 9 ll abs(ll x) { return x>0?x:-x; } 10 11 ll cal(int p) 12 { 13 int i; ll t=0; 14 for (i=1;i<=n;i++) 15 if (w[i]>=p) num[i]=num[i-1]+1,sum[i]=sum[i-1]+v[i]; 16 else num[i]=num[i-1],sum[i]=sum[i-1]; 17 for (i=1;i<=m;i++) t+=(num[r[i]]-num[l[i]-1])*(sum[r[i]]-sum[l[i]-1]); 18 return t; 19 } 20 21 int main() 22 { 23 scanf("%d%d%lld",&n,&m,&s),mn=1000003; 24 for (i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]),mx=max(mx,w[i]),mn=min(mn,w[i]); 25 for (i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i]); 26 for (h=mn,t=++mx;h<t;) 27 { 28 mid=h+t>>1; 29 if (cal(mid)>s) h=mid+1; 30 else t=mid,k=mid; 31 } 32 if (cal(h)-s<cal(k)-s) k=h; 33 printf("%lld\n",abs(min(s-cal(k),cal(k-1)-s))); 34 return 0; 35 }
我一直在繁华的苍凉中徘徊着,用一颗OI的心寻找着生命和宇宙的美妙与玄奥。