题解 P1314 【聪明的质监员】
** woc 看到提高+吓我一跳= =
我想说这道题主要是在考语文!!!!
然后是二分W的值和前缀和优化(别的二分有一种优化是对有序数组二分下标,但是这里不适用)
主要坑点在于:S可以达到10^12 ,所以一是要防止数组爆掉(变量也是一样),二是函数的返回类型,比如check(或者还要做死写个优读,像我这样的)返回值为long long,三是最小值最大值要够!!不要赋成10^10,这个最值对于其中45分的数据是不够大的
目测至少到10^12 [delete]我因为这三点起码WA了5次QAQ,唉[/delete]
其余的,注意是差的绝对值的最小值,假如对于当前M算出结果是ans,那么要取
abs(ans-S)的最小值,不要只取ans-S的最小值
**
//代码好像有点长= =我写的拙劣
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const long long maxn=200000+10;
const long long INF=(1<<30);
typedef long long ll;
ll n,m,S; //我实在不想过于纠结哪些要用long long 哪些是int 还有哪些计算乘积的时候要强制转换,所以直接全部long long 了
ll w[maxn],v[maxn];
ll sum[maxn],cnt[maxn];
ll l[maxn],r[maxn];
inline ll read()
{
ll ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
ll mind=INF*1000; //最大值一定要够!!!
ll cal(ll k)
{
ll ret=0;
sum[0]=cnt[0]=0;
for(int i=1;i<=n;i++)
if(w[i]>=k)
cnt[i]=cnt[i-1]+1,sum[i]=sum[i-1]+v[i];
else cnt[i]=cnt[i-1],sum[i]=sum[i-1];
for(int i=1;i<=m;i++)
{
ret = ret+(cnt[r[i]]-cnt[l[i]-1])*(sum[r[i]]-sum[l[i]-1]);
if(ret-S>S) return ret;
}
return ret;
}
inline ll max(const ll &a,const ll &b)
{
if(a>b) return a;
return b;
}
inline ll min(const ll &a,const ll &b)
{
if(a>b) return b;
return a;
}
int main()
{
cin>>n>>m>>S;
ll maxw=-INF,minw=INF; //w最大值只有10^6 这样应该是够得
for(int i=1;i<=n;i++)
{
w[i]=read();v[i]=read();
maxw=max(maxw,w[i]);
minw=min(minw,w[i]);
}
for(int i=1;i<=m;i++)
{
l[i]=read();r[i]=read();
}
ll lt=minw,rt=maxw;
while(lt<=rt)
{
ll mid=lt+(rt-lt)/2;
ll tmp=cal(mid);
if(tmp==S)
{
mind=0;break;
}
else if(tmp>S)
{
lt=mid+1;
if(tmp-S<mind)
{
mind=tmp-S;
}
}
else rt=mid-1,mind=min(mind,S-tmp);
}
cout<<mind;
return 0;
}