JZOJ 5440. 【NOIP2017提高A组冲刺11.1】背包

来源:互联网 发布:mac双系统移除win8后 编辑:程序博客网 时间:2024/06/05 05:43

题目大意

有n种商品,第i种物品的价格为ai,价值为bi。有m个人来购买商品,每个人每种物品只能购买一个。第j个人有cj的钱,他会不停选择一个能买得起的价格最高的商品买走(如果有多个则选择价值最高的)。你需要求出每个人购买的物品的价值和。
100%的数据,n,m<=100000,ai,bi,cj<=1012

题解

有几个性质:
①选择商品的法则唯一:每次选择目前≤cj的ai,如果ai相同就买bi最大的。
有两种解法:
先按照ai从小到大排序,如果ai相等就按照bi从小到大排。那么每次选最右边的合法商品。
第一种,直接二分。这个很方便。因为右节点不断左移,然后暴力二分即可(维护个前缀,因为能卖一整个区间就买一整个区间)。
第二种,线段树(比较麻烦,但是容易想)。直接每次找最右边的区间。
但是,选完最右边一个合法的区间之后,还有剩余的钱买商品怎么办?还要往左找。
所以,这个地方有点难操作。
可以利用全局变量,求出买完右边合法区间之后剩下来的钱(如果要选择右边合法区间的话。具体看代码)。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define N 100010#define LL long long#define P(a) putchar(a)#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;struct note{    LL sa,sb,mn;};note tr[N*20];struct note1{    LL a,b;};note1 a[N];LL c[N];LL n,m,i,ans,R,x1;LL read(){    LL fh=1,res=0;char ch;    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();    if(ch=='-')fh=-1,ch=getchar();    while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();    return res*fh;}void write(LL x){    if(x>9)write(x/10);    P(x%10+'0');}void writeln(LL x){write(x);P('\n');}void update(LL ps){    tr[ps].sa=tr[ps<<1].sa+tr[(ps<<1)+1].sa;    tr[ps].sb=tr[ps<<1].sb+tr[(ps<<1)+1].sb;    tr[ps].mn=tr[ps<<1].mn<tr[(ps<<1)+1].mn?tr[ps<<1].mn:tr[(ps<<1)+1].mn;}void build(LL ps,LL l,LL r){    if(l==r){        tr[ps].sa=a[l].a;        tr[ps].sb=a[l].b;        tr[ps].mn=a[l].a;        return;    }    LL wz=(l+r)>>1;    build(ps<<1,l,wz);    build((ps<<1)+1,wz+1,r);    update(ps);}void find(LL ps,LL l,LL r,LL x,LL bl){    if(bl)x1=x;    if(!x)return;    if(l==r){        if(x>=tr[ps].sa){            ans+=tr[ps].sb;            if(bl)x1=x-tr[ps].sa;        }        return;    }    LL wz=(l+r)>>1;    if(x>=tr[(ps<<1)+1].sa){        ans+=tr[(ps<<1)+1].sb;        find(ps<<1,l,wz,x-tr[(ps<<1)+1].sa,bl);    } else{        if(x>=tr[(ps<<1)+1].mn){            find((ps<<1)+1,wz+1,r,x,1);            find(ps<<1,l,wz,x1,bl);        } else        if(x>=tr[ps<<1].mn){            find(ps<<1,l,wz,x,bl);        }    }}bool cmp(note1 x,note1 y){return x.a<y.a || (x.a==y.a && x.b<y.b);}int main(){    n=read(),m=read();    fo(i,1,n)a[i].a=read(),a[i].b=read();    sort(a+1,a+n+1,cmp);    build(1,1,n);    fo(i,1,m){        c[i]=read();ans=0;R=c[i];        find(1,1,n,R,0);        writeln(ans);    }    return 0;}
阅读全文
1 0
原创粉丝点击