NOIP2011day2 聰明的質檢員(二分+字首和)
題意
個礦石,每個礦石有
兩個引數,分別代表它的質量和價值,給定
思路
說白了就是取一個
, 使
個區間中各自質量不比
小的礦石價值乘上這個區間滿足數,使總貢獻與
最接近。
不難發現,
越小,總貢獻越大,那麼可以二分
,求出一個最大的
使得總貢獻小於等於
,再在這個值附近找答案即可。
程式碼
#include<bits/stdc++.h>
#define FOR(i,x,y) for(register int i=(x);i<=(y);++i)
#define DOR(i,x,y) for(register int i=(x);i>=(y);--i)
#define N 200003
typedef long long LL;
using namespace std;
void Read(int &x)
{
x=0;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
}
struct node{int w,v;}a[N];
int L[N],R[N],disc[N],n,m;
LL s[N],cnt[N],S,ans;
LL ABS(LL x){if(x<0)return -x;return x;}
LL solve(LL W)
{
LL sum=0;
FOR(i,1,n)
{
if(a[i].w>=W)cnt[i]=1,s[i]=a[i].v;
else cnt[i]=s[i]=0;
}
FOR(i,2,n)cnt[i]+=cnt[i-1],s[i]+=s[i-1];
FOR(i,1,m)sum+=(cnt[R[i]]-cnt[L[i]-1])*(s[R[i]]-s[L[i]-1]);
return sum;
}
int main()
{
scanf("%d%d%lld",&n,&m,&S);
FOR(i,1,n)Read(a[i].w),Read(a[i].v),disc[i]=a[i].w;
sort(disc+1,disc+1+n);
int tot=unique(disc+1,disc+1+n)-disc-1;
FOR(i,1,n)a[i].w=lower_bound(disc+1,disc+1+tot,a[i].w)-disc;
FOR(i,1,m)Read(L[i]),Read(R[i]);
ans=1e18;
int l=0,r=tot+1;
while(l<r)
{
int mid=l+r>>1;
if(solve(mid)<=S)
r=mid;
else l=mid+1;
}
FOR(i,-3,3)
ans=min(ans,ABS(S-solve(l+i)));
printf("%lld\n",ans);
return 0;
}