购买书籍
【描述】
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;
}