题目描述
蛤布斯有nn种商品,第ii种物品的价格为aiai,价值为bibi。有mm个人来向蛤布斯购买商品,每个人每种物品只能购买一个。第jj个人有cjcj的钱,他会不停选择一个能买得起的价格最高的商品买走(如果有多个则选择价值最高的)。你需要求出每个人购买的物品的价值和。
输入数据
第一行两个正整数nn,mm。接下来nn行每行两个正整数aiai,bibi。接下来mm行每行一个正整数cjcj。
输出数据
mm行,每行一个整数表示答案。
样例输入
5 4
10 5
9 8
7 3
3 4
1 2
20
100
28
18
样例输出
15
22
18
10
数据范围
对于20%的数据,n,m]≤1000n,m]≤1000。
对于另外30%的数据,ai,bi,cjai,bi,cj在[1,1012][1,1012]中均匀随机。
对于100%的数据,n,m≤100000,ai,bi,cj≤1012n,m≤100000,ai,bi,cj≤1012。
题目分析
这一题挺有趣的,至少我是这么觉得。我没有想到二分答案的思路,我只想到了排序,然后暴力。接下来我们发现这是构造一个不连续单调的数列,我们可以先处理处前缀和,我想不到这一点。我们两次二分答案,然后得出左右区间即可。
#include<bits/stdc++.h> using namespace std; #define int long long #define N 100001 #define IL inline IL char gc(){ static char buf[1000001],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; }IL void write(int x){ if(x>9)write(x/10); putchar(x%10^48); }template<class T>IL int read(T &x){ x=0;register char c=gc(); while(c<47)c=gc(); while(c>47)x=x*10+(c^48),c=gc(); }struct aa{int a,b; friend bool operator<(const aa&x,const aa&y){ return (x.a^y.a)?x.a<y.a:x.b<y.b;}}a[N]; int sum[N],sum2[N],n,m; IL int find1(int l,int r,int x){ int ans=-1,m; while (l<=r){ m=(l+r)>>1; a[m].a<=x?ans=m,l=m+1:r=m-1; }return ans; }IL int find2(int l,int r,int x){ int ans=-1,m; while (l<=r){ m=(l+r)>>1; sum[m]>=x?ans=m,r=m-1:l=m+1; }return ans; }IL int check(int R,int res){ int ans=0,r=find1(1,R,res); if (r==-1) return 0; int l=find2(0,r-1,sum[r]-res); if (l^-1) ans+=sum2[r]-sum2[l]; return ans+check(l,res-sum[r]+sum[l]); }signed main(){ freopen("pack.in","r",stdin),freopen("pack.out","w",stdout); read(n),read(m); for (register int i=1;i<=n;i++) read(a[i].a),read(a[i].b); sort(a+1,a+n+1); for (register int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].a,sum2[i]=sum2[i-1]+a[i].b; for (register int sum,i=1;i<=m;i++) read(sum),write(check(n,sum)),putchar('\n'); return 0; }
代码说明
二分答案可以用upper_bound实现,zzq大佬的代码就是这么实现的。我不给代码,溜了。
尾声:详见下期
浙公网安备 33010602011771号