小明买年糕
Description
过年了,小明准备去超市买年糕,超市里共有nn种年糕,每种年糕数量无限多,从1~n编号,每种年糕有自己的价格wi和美味值vi。小明选购年糕的过程如下:
1、小明打算去买m次年糕,每次选购区间[Li, Ri]内的年糕,每种年糕每次只能买一个;
2、每次选购都用事先准备好的购物袋,购物袋可以装任意数量的物品,但是这个购物袋只装价格wi不小于W的年糕,区间内所有满足条件的年糕都必须要买;
3、每次出去购买年糕都会产生一个幸福值Yi,它的计算的公式为:
其中符号[条件]的意思是:若条件为真,值就是1,否则值就是0;
所以小明m次选购年糕行动所产生的总幸福值为:
小明是一个精简持家的程序员,所以他选购年糕有一个标准值S。他想通过调整事先准备的购物袋的W值,让年糕总幸福值尽量接近S,即使得S−H的绝对值最小。现在请你帮忙调整购物袋的W值,使得∣S−H∣绝对值最小,并输出这个最小值。
Input
第一行包括三个整数n, m, S,分别表示年糕的种类,购物的次数和标准值。
Output
一个整数,表示所求最小值。
Sample Input 1
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
Sample Output 1
10
这道题,一看之下就知道要用二分了(无脑二分)但关键是每一次的区间查询都会用掉不少时间,如果这么写:
for (int i=1; i<=m; i++)
for (int j=l[i]; j<=r[i]; j++)
然后就T了。。。所以我们需要简化----(前缀和)
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define mac 200050
#define debug(n) printf("%d ",n)
#define ll long long
struct st
{
int w,v;
}food[mac];
int l[mac],r[mac],n,m;
ll d[mac],dy[mac],s;
ll ok(int x);
ll abs(ll x)
{
return x>0?x:-x;
}
int main()
{
scanf ("%d%d%lld",&n,&m,&s);
for (int i=1; i<=n; i++){
scanf ("%d%d",&food[i].w,&food[i].v);
}
for (int i=1; i<=m; i++){
scanf ("%d%d",&l[i],&r[i]);
}
int L=0,R=1e6+10,id;
ll ans=1e18;
for (int i=1; i<=20; i++){
int mid=(L+R)>>1;
ll sum=ok(mid);
if (abs(sum-s)<ans){ //二分答案,相差较小就更新
ans=abs(sum-s);
id=mid;
}
if (sum>s) L=mid+1; //如果太大,说明太幸福了,W需要往上调,减少购买
else R=mid-1;
}
printf ("%lld\n",ans);
return 0;
}
ll ok(int x)
{
ll aans=0;
memset(d,0,sizeof(d));
memset(dy,0,sizeof(dy));
for (int i=1; i<=n; i++){
if (food[i].w>x) {
d[i]=d[i-1]+food[i].v;
dy[i]=dy[i-1]+1;
}
else {
d[i]=d[i-1];
dy[i]=dy[i-1];
}
} //求大于x的前缀和
for (int i=1; i<=m; i++){
aans+=(d[r[i]]-d[l[i]-1])*(dy[r[i]]-dy[l[i]-1]);
}
return aans;
}