SSL2834 2017年11月4日提高组T2 背包(二分)

来源:互联网 发布:mac系统word画流程图 编辑:程序博客网 时间:2024/05/16 18:05

2017年11月4日提高组T2 背包

Description

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

Input

第一行两个正整数n,m。接下来n行每行两个正整数ai,bi。接下来m行每行一个正整数cj。

Output

m行,每行一个整数表示答案。

Sample Input

5 4
10 5
9 8
7 3
3 4
1 2
20
100
28
18
Sample Output

15
22
18
10
Hint

【数据规模和约定】
20%的数据,n,m<=1000。
100%的数据,n,m<=100000,ai,bi,cj<=10^12。

分析:每次二分一下当前能买的价值最高的物品,然后再二分一下能买的连续一段的长度。由于每次买走一段以后钱至少减少一半,因此每个人只会二分 log 次。

代码

#include <cstdio>#include <algorithm>#define N 100005#define ll long longusing namespace std;struct arr{    ll x,y;}a[N];ll p[N],sumx[N],sumy[N],n,m;int so(arr u,arr v){    if (u.x==v.x) return u.y>v.y;    return u.x>v.x;}int find(int o,ll sump){    int l=o,r=n;    while (l<r)    {        int mid=(l+r)/2;        ll sum=sumx[mid]-sumx[o-1];        if (sum<=sump) l=mid+1;            else r=mid;    }    if (sumx[l]-sumx[o-1]>sump) l--;    return l;}int main(){    //freopen("pack.in","r",stdin);    //freopen("pack.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++)        scanf("%lld%lld",&a[i].x,&a[i].y);    for (int i=1;i<=m;i++)        scanf("%lld",&p[i]);    sort(a+1,a+n+1,so);    for (int i=1;i<=n;i++)    {        sumx[i]=sumx[i-1]+a[i].x;        sumy[i]=sumy[i-1]+a[i].y;    }    for (int i=1;i<=m;i++)    {        ll ans=0;        int s=0;        while (p[i]>=a[n].x)        {            int l=s+1,r=n+1;            while (l<r)            {                int mid=(l+r)/2;                if (a[mid].x>p[i]) l=mid+1;                    else r=mid;            }            s=find(l,p[i]);            p[i]-=sumx[s]-sumx[l-1];            ans+=sumy[s]-sumy[l-1];            if (s==n) break;        }        printf("%lld\n",ans);    }    fclose(stdin);    fclose(stdout);}
原创粉丝点击