【2018/10/01】T3
購買書籍 【描述】 L的書籍被 M偷了以後傷心欲絕,決定再購買一些回來,現在有 N 本書可以買,每本書的價格是 a[i]元。 現在L總共有 M 元,以及 K 張優惠券。 對於每本書,如果使用一張優惠券,則可以用b[i]的優惠價格購買。 注意每本書只能使用一張優惠券,只能購買一次。 L想知道自己最多可以購買幾本書? 【 輸入】 第一行三個整數 N, K, M 接下來 N 行,每行兩個整數,表示 a[i]和 b [i]。 【 輸出】 一個整數表示答案。 【 Sample Input】 4 1 7 3 2 2 2 8 1 4 3 【 Sample Output】 3 【解釋】 選擇第 1、 2、 3 本書,其中第3本使用優惠券。總共 5 元。 【資料規模】 對於 20%:N<=10 對於 50%:N<=100 對於另外 20%:K = 0 對於 100%:1 <= N <= 100000,0 <= K <= N,M <= 10^14,1 <= b[i] <= a[i] <= 10^9
分析
%%%%%偽貪心水過資料……zxy大佬強勢出資料卡死我的假AC,嗚嗚嗚~~~~%%%%%%
先說一下假思路吧:
就是列舉前k小的優惠劵,並且就用這些,然後如果還剩了錢,就繼續買原價最小的,直到沒錢為止
zxy大佬的資料:
9 5 29 2 1 3 1 100 3 102 5 1006 4 100 4 4 2 3 2 1005 1
正確答案: 9
我的程式碼:6
放上我的假程式碼:
#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]; ll m; struct node{ int a,b,pp; }p[N]; bool cmp(const node &x,const node &y){ return x.b<y.b;} int main(){ n=in;k=in;scanf("%lld",&m); int i,j; for(i=1;i<=n;++i){ a[i]=in;b[i]=in; p[i].a=a[i];p[i].b=b[i]; p[i].pp=i; } if(k==0||k==n){ if(k==n) memcpy(a,b,sizeof(a)); sort(a+1,a+n+1); ll sum=0; for(i=1;i<=n;++i) { sum+=1ll*a[i]; if(sum>m){ printf("%d",i-1); return 0; } } printf("%d",n); return 0; } sort(p+1,p+n+1,cmp); for(i=1;i<=k;++i) a[p[i].pp]=p[i].b; sort(a+1,a+n+1); ll sum=0; for(i=1;i<=n;++i) { sum+=1ll*a[i]; if(sum>m){ printf("%d",i-1); return 0; } } printf("%d",n); return 0; }
好吧,還是來胡搞一下正解: 其實也就是在我的假思路基礎上,修正一下這個貪心,加上一個類似網路流的退流操作就可以啦
具體思路:
先選出優惠價最小的 k 個,如果此時價格大於了 m 就直接輸出當前記錄的個數
否則,我們就開始在此基礎上擴充套件最優解
我們首先用一個 set 來記錄下優惠價最小的那 k 個,他們原價和優惠價的差值
然後列舉後面的書,分為兩種情況:
1.直接用a[ i ] 來買
2.推掉一個優惠券,並用這個優惠券去買剩下的書中優惠價最小的那一個。此時需要付的錢就是 推掉的那個優惠券所對應的差價,加上當前的優惠價
這兩個情況中選取一個所花錢小的
嗯……就是這樣
程式碼
#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;
}