背包
【问题描述】
蛤布斯有 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 }