2018.10.01【校內模擬】購買書籍(貪心)(堆)(set實現堆)
描述
L的書籍被M偷了以後傷心欲絕,決定再購買一些回來,現在有 N 本書可以買,每本書的價格是 a[i]元。
現在L總共有 M 元,以及 K 張優惠券。 對於每本書,如果使用一張優惠券,則可以用b[i]的優惠價格購買。 注意每本書只能使用一張優惠券,只能購買一次。
L想知道自己最多可以購買幾本書?
輸入
第一行三個整數 N, K, M
接下來 N 行,每行兩個整數,表示 a[i]和 b [i]。
輸出
一個整數表示答案。
樣例輸入
一個整數表示答案。
樣例輸出
3
提示
【解釋】
選擇第 1、 2、 3 本書,其中第3本使用優惠券。總共 5 元。
【資料規模】
對於 20%:N<=10
對於 50%:N<=100
對於另外 20%:K = 0
對於 100%:1<=N<=100000,0<=K<=N,M<=1014,1<=b[i]<=a[i]<=109
解析:
場上寫了70分暴力結果因為讀入優化寫掛而光榮爆0的蒟蒻。現在來發一個沒人看的題解。
思路:
這道題貪心很好想啊,中等資料動態規劃也很好想啊。 中等資料就是做一個揹包問題就好了啊。
而大資料隨機化貪心的蒟蒻就直接涼涼了。
因為資料範圍實在是很大,貪心幾次就T了。
然而這道題有淺顯易懂的一句話題解。。。
先使用 K 張優惠券,買價格最小的。 如果考慮如何擴充套件當前解 1、 直接購買一個 a[i] 2、退掉一個用優惠券的,用優惠券去買別的 b[j]+(a[i]-b[i]) 2 種情況看哪一個更優 用堆維護 a[i], b[i], a[i]-b[i]
好吧這是六句
而擴充套件到不能夠再次擴充套件的情況下就是最優了,因為我們從構造方案來說,每次的選取都是向著 儘可能多拿,少花錢 的原則做的。
其實可以用網路流退流操作理解一下。但是如果真的寫網路流光建圖就gg了。
注意實現的時候有點問題。 我們選擇了一個物品以優惠價或全價購買,它在另一個集合裡面就要刪除。 而如果真的寫堆的話就要手寫,每次刪除就是當前節點到,然後。
寫起來很麻煩,所以就直接上一個模擬堆就行了。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const
inline char get_char(){
static const int Rlen=1<<18;
static char buf[Rlen],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline
ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=100006;
struct node{
int a,b;
}p[N];
inline bool cmp1(cs node &a,cs node &b){
return a.a<b.a;
}
inline bool cmp3(cs node &a,cs node &b){
return a.b<b.b;
}
set<int> s1;
set<pair<int,int> > s2,s3;
int n,k;
ll m;
int ans;
signed main(){
n=getint();
k=getint();
m=getint();
for(int re i=1;i<=n;++i)p[i].a=getint(),p[i].b=getint();
if(k==0){
sort(p+1,p+n+1,cmp1);
for(int re i=1;i<=n;++i){
if(m>=p[i].a)m-=p[i].a,++ans;
else break;
}
cout<<ans<<endl;
return 0;
}
sort(p+1,p+n+1,cmp3);
for(int re i=1;i<=min(n,k);++i){
if(m>=p[i].b)m-=p[i].b,++ans,s1.insert(p[i].a-p[i].b);
else return cout<<ans<<endl,0;
}
s2.clear();
s3.clear();
for(int re i=k+1;i<=n;++i){
s2.insert(make_pair(p[i].b,i));
s3.insert(make_pair(p[i].a,i));
}
while(!s2.empty()){
ll f1=*s1.begin()+s2.begin()->first,f2=s3.begin()->first;
if(f1<=f2){
if(m>=f1)m-=f1,++ans;
else break;
int id=s2.begin()->second;
s3.erase(make_pair(p[id].a,id));
s1.erase(s1.begin());
s2.erase(s2.begin());
s1.insert(p[id].a-p[id].b);
}
else {
if(m>=f2)m-=f2,++ans;
else break;
int id=s3.begin()->second;
s3.erase(s3.begin());
s2.erase(make_pair(p[id].b,id));
}
}
cout<<ans<<endl;
return 0;
}