正题
题目链接:http://noip.ybtoj.com.cn/contest/105/problem/1
题目大意
nnn个物品,每个价格为viv_ivi有xix_ixi个,mmm次,开始有wiw_iwi元。每次选择能买的最贵的买,求能买多少。
解题思路
分两种情况讨论,如果wi≥xnoww_i\geq x_{now}wi≥xnow那么就二分出一个位置使得买到这里后不能再买了,然后nownownow跳过去。如果wi<xnoww_i< x_{now}wi<xnow,那么二分出一个位置使得wi≥xnoww_i\geq x_{now}wi≥xnow然后nownownow跳过去。
这样每次wiw_iwi会减少一半,所以时间复杂度是O(qlogwilogn)O(q\log w_i\log n)O(qlogwilogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10;
struct node{ll v,x;
}a[N];
ll n,m,b[N],s[N],k[N];
bool cmp(node x,node y)
{return x.v>y.v;}
int main()
{freopen("present.in","r",stdin);freopen("present.out","w",stdout);scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++)scanf("%lld%lld",&a[i].v,&a[i].x);sort(a+1,a+1+n,cmp);for(ll i=1;i<=n;i++)b[i]=b[i-1]+a[i].v*a[i].x,s[i]=s[i-1]+a[i].x,k[n-i+1]=a[i].v;while(m--){ll q,ans=0,x=0;scanf("%lld",&q);while(x<=n&&q){if(q>=a[x+1].v){ll y=lower_bound(b+x+1,b+1+n,q+b[x])-b;if(y==x)break;ans+=s[y-1]-s[x];q-=b[y-1]-b[x];x=y;if(x>n)break;ans+=q/a[x].v;q%=a[x].v;}else{ll y=upper_bound(k+1,k+1+n,q)-k-1;if(!y)break;x=n-y;}}printf("%lld\n",ans);}
}