1. 程式人生 > >nssl1148,jzoj5461-購物【可撤回貪心,堆】

nssl1148,jzoj5461-購物【可撤回貪心,堆】

正題

題目大意

有n個物品,m元,k個打折券。 每個物品打折前pi元,打折後qi元,求最多能買多少物品。

解題思路

用可撤回貪心。 先將p和q分開排序,然後前k個都用打折劵。之和我們考慮一個新的東西如果必須打折的話,那麼就相當於用pminiqmini元買一個打折卷,所以我們用堆用最大的進行比較買不買打折券好

code

#include<cstdio>
#include<algorithm>
#include<queue>
#define N 100010
using namespace std;
struct node{
    long long w,num;
}q[N]
,p[N]; long long n,k,m,ans; priority_queue <int> K; bool f[N]; bool cmp(node x,node y) {return x.w<y.w;} int main() { scanf("%lld%lld%lld",&n,&k,&m); for(long long i=1;i<=n;i++) { scanf("%lld%lld",&p[i].w,&q[i].w); p[i].num=q[i].num=i; } sort
(p+1,p+1+n,cmp); sort(q+1,q+1+n,cmp);//分開排序 long long j=1; for(long long i=1;i<=n;i++) { if(k)//前k個全要 { if(m>=q[i].w) { m-=q[i].w; f[q[i].num]=true; K.push(q[i].w-p[q[i].num].w); ans++;k--; } } else
{ while(f[j]&&j<n)j++;//走到沒有用過的 if(m>=min(p[j].w,q[i].w-K.top()))//買的起 { m-=min(p[j].w,q[i].w-K.top()); if(p[j].w>q[i].w-K.top()) { m-=q[i].w-K.top(); K.pop(); K.push(q[i].w-p[q[i].num].w);//壓入堆 } else j++;//下一個最小的 ans++;//多買一個 } } } printf("%lld",ans); }