[noip2011d2t2]聪明的质检员 二分+前缀和优化

近期卡的时间最长的一道题了qaq

题目链接:https://www.luogu.org/problem/show?pid=1314

光理解那个公式就理解了半天

 每个区间的Y值=(该区间重量大于选定的W的点的个数)*(这些点的价值之和)

读懂题意后,可以发现显然Y随着W的增大而减小,具有单调性

由此可以想到二分

那么对于二分的每个W值,要如何求出检验值Y呢?

对于每个区间一一判断显然不满足数据规模

因为W值确定之后,每个点对答案有无贡献就已经确定。因此可以对于每个W值,预处理出一个类似于前缀和的数组储存满足条件的点的信息

就可以在O(m)的时间内算出Y值

这个优化方法要熟练运用==

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #define ll long long
 6 #define inf (1LL<<60)
 7 using namespace std;
 8 const int maxn=200200;
 9 const int maxm=200200;
10 ll n,m,s;
11 ll minw,maxw;
12 ll w[maxn],v[maxn],L[maxm],R[maxm];
13 ll cnt[maxn],sum[maxn];
14 ll read(){
15     ll x=0;
16     char ch=getchar();
17     while (ch<'0'||ch>'9') ch=getchar();
18     while (ch>='0'&&ch<='9'){
19         x=x*10+ch-'0';
20         ch=getchar();
21     }
22     return x;
23 }
24 ll check(ll W){
25     memset(cnt,0,sizeof(cnt));
26     memset(sum,0,sizeof(sum));
27     for (ll i=1;i<=n;i++){
28         cnt[i]=cnt[i-1];
29         sum[i]=sum[i-1];
30         if (w[i]>=W){
31             cnt[i]++;
32             sum[i]+=v[i];
33         }
34     }
35     ll tmp=0;
36     for (ll i=1;i<=m;i++)
37         tmp+=(cnt[R[i]]-cnt[L[i]-1])*(sum[R[i]]-sum[L[i]-1]);
38     return tmp;
39 }
40 int main(){
41     n=read(),m=read(),s=read();
42     maxw=0;
43     for (ll i=1;i<=n;i++){
44         w[i]=read(),v[i]=read();
45         maxw=max(maxw,w[i]);
46     } 
47     for (ll i=1;i<=m;i++){
48         L[i]=read(),R[i]=read();
49     }
50     ll l=0,r=maxw+1,ans=inf;
51     while (l<=r){
52         ll mid=(l+r)>>1;
53         ll t=check(mid);
54         ans=min(ans,abs(t-s));
55         if (t<s) r=mid-1;
56         else l=mid+1;
57     }
58     printf("%lld\n",ans);
59     return 0;
60 }
View Code

 

11天倒计时

posted @ 2017-10-30 21:43  Vincent_hwh  阅读(256)  评论(0编辑  收藏  举报