【2018/10/01測試T3】【WOJ 4010】購買書籍
阿新 • • 發佈:2018-12-13
【題目】
題目描述:
L 的書籍被 M 偷了以後傷心欲絕,決定再購買一些回來,現在有 N 本書可以買,每本書的價格是 a[ i ]元。
現在 L 總共有 M 元,以及 K 張優惠券。 對於每本書,如果使用一張優惠券,則可以用b[i]的優惠價格購買。 注意每本書只能使用一張優惠券,只能購買一次。
L想知道自己最多可以購買幾本書?
輸入格式:
第一行三個整數 N , K , M
接下來 N 行,每行兩個整數,表示 a[ i ] 和 b[ i ]。
輸出格式:
一個整數表示答案。
樣例資料:
輸入
4 1 7 3 2 2 2 8 1 4 3
輸出
3
備註:
【解釋】
選擇第 1、 2、 3 本書,其中第 3 本使用優惠券。總共 5 元。
【資料規模】
對於 20%:N ≤ 10
對於 50%:N ≤ 100
對於另外 20%:K = 0
對於 100%:1 ≤ N ≤ 100000,0 ≤ K ≤ N,M ≤ ,1 ≤ b[ i ] ≤ a[ i ] ≤
【分析】
用一個錯解 A 了,資料太水
對於100%資料: 貪心
先使用K張優惠券,買價格最小的。
如果考慮如何擴充套件當前解 :
1、直接購買一個 a[ i ] 2、退掉一個用優惠券的,用優惠券去買別的 b[ j ] + ( a[ i ] - b[ i ] )
2 種情況看哪一個更優
用堆維護 a[ i ], b[ i ], a[ i ] - b[ i ]
【程式碼】
#include<bits/stdc++.h> #define in read() #define N 100009 #define ll long long using namespace std; inline int read(){ char ch;int res=0; while((ch=getchar())<'0'||ch>'9'); while(ch>='0'&&ch<='9'){ res=(res<<3)+(res<<1)+ch-'0'; ch=getchar(); } return res; } int n,k,a[N],b[N],id[N]; ll m; set<pair<int,int> > s1,s2,s3; bool cmp(int x,int y){return b[x]<b[y];} int main(){ n=in;k=in;scanf("%lld",&m); for(int i=1;i<=n;++i){ a[i]=in;b[i]=in; id[i]=i; } sort(id+1,id+n+1,cmp); if(k==0){//特殊的特判一下 sort(a+1,a+n+1);ll sum=0; for(int i=1;i<=n;++i){ sum+=a[i]; if(sum>m) { printf("%d",i-1); return 0; } } printf("%d",n); return 0; } ll now=0;int ans=0; for(int i=1;i<=k;++i){ now+=b[id[i]];if(now>m) { return printf("%d",ans),0; } ++ans; s1.insert(make_pair(a[id[i]]-b[id[i]],id[i]));//差值 } for(int i=k+1;i<=n;++i){ s2.insert(make_pair(b[id[i]],id[i]));//優惠價 s3.insert(make_pair(a[id[i]],id[i]));//原價 } while(s2.size()){ ll f1=s1.begin()->first+s2.begin()->first,f2=s3.begin()->first; if(f1<f2){ now+=f1;if(now>m) return printf("%d",ans),0; ans++;int u=s2.begin()->second; s1.erase(s1.begin());s2.erase(s2.begin()); s1.insert(make_pair(a[u]-b[u],u));s3.erase(s3.find(make_pair(a[u],u))); } else{ now+=f2;if(now>m) return printf("%d",ans),0; ans++;int u=s3.begin()->second; s3.erase(s3.begin());s2.erase(s2.find(make_pair(b[u],u))); } } printf("%d",ans); return 0; }