您的位置:首页 > 其它

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

2017-11-05 19:38 344 查看

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 long
using namespace std;

struct arr
{
ll x,y;
}a
;
ll p
,sumx
,sumy
,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
.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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: