背包

【问题描述】
蛤布斯有 n 种商品,第 i 种物品的价格为 ai,价值为 bi。有 m 个人来向蛤
布斯购买商品,每个人每种物品只能购买一个。第 j 个人有 cj 的钱,他会不停
选择一个能买得起的价格最高的商品买走(如果有多个则选择价值最高的)。你
需要求出每个人购买的物品的价值和。
【输入格式】
第一行两个正整数 n,m。接下来 n 行每行两个正整数 ai,bi。接下来 m 行
每行一个正整数 cj。
【输出格式】
m 行,每行一个整数表示答案。
【样例输入输出】
pack.in
5 4
10 5
9 8
7 3
3 4
1 2
20
100
28
18
pack.out
15
22
18
10
【数据范围】
对于 20%的数据,n,m<=1000。
对于另外 30%的数据,ai,bi,cj 在[1,10^12]中均匀随机。
对于 100%的数据,n,m<=100000,ai,bi,cj<=10^12。

不能一个一个二分查找,因为有可能会全部都可以买,被卡掉

排序是肯定的

所以算出前缀和,每一次二分找到一个小于c的最大价格物品R

再二分一个下界使得sum[R]-sum[L]<=c,然后把剩余价格递归

可以证明递归次数<=logc

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long lol;
 7 struct FFF
 8 {
 9   lol a,b;
10 }a[100001];
11 lol sum[100001],sum2[100001],n,m;
12 bool cmp(FFF a,FFF b)
13 {
14   return a.a<b.a||(a.a==b.a&&a.b<b.b);
15 }
16 int find1(int l,int r,lol x)
17 {
18   lol as=-1;
19   while (l<=r)
20     {
21       int mid=(l+r)/2;
22       if (a[mid].a<=x) as=mid,l=mid+1;
23       else r=mid-1;
24     }
25   return as;
26 }
27 int find2(int l,int r,lol x)
28 {
29   lol as=-1;
30   while (l<=r)
31     {
32       int mid=(l+r)/2;
33       if (sum[mid]>=x) as=mid,r=mid-1;
34       else l=mid+1;
35     }
36   return as;
37 }
38 lol count(int R,lol C)
39 {
40   lol s=0;
41   int r=find1(1,R,C);
42   if (r==-1) return 0;
43   int l=find2(0,r-1,sum[r]-C);
44     if (l!=-1)
45       s+=sum2[r]-sum2[l];
46     return s+count(l,C-sum[r]+sum[l]);
47 }
48 int main()
49 {lol c,i;
50   cin>>n>>m;
51   for (i=1;i<=n;i++)
52     {
53       scanf("%lld%lld",&a[i].a,&a[i].b);
54     }
55   sort(a+1,a+n+1,cmp);
56   for (i=1;i<=n;i++)
57     sum[i]=sum[i-1]+a[i].a,sum2[i]=sum2[i-1]+a[i].b;
58   for (i=1;i<=m;i++)
59     {
60       scanf("%lld",&c);
61       printf("%lld\n",count(n,c));
62     }
63 }

 

posted @ 2017-11-06 14:26  Z-Y-Y-S  阅读(269)  评论(0编辑  收藏  举报