小清新数据结构题。
令已经确定被购买的奶牛的集合为 \(S\)。
注意到必然存在一个最优解使得集合 \(S\) 中 \(P_i-C_i\) 前 \(k\) 大的奶牛使用了优惠券。
证明:
令使用优惠券的集合为 \(S'\),显然有 \(|S'|=k\),则花费为:
\[\sum_{i\in S\wedge i\notin S'}P_i+\sum_{i\in S'}C_i \\ =\sum_{i\in S}P_i-\sum_{i\in S'}P_i+\sum_{i\in S'}C_i \\ =\sum_{i\in S}P_i-\sum_{i\in S'}(P_i-C_i) \\ \]
其中 \(\sum_{i\in S}P_i\) 为定值。
不难发现 \(\sum_{i\in S'}(P_i-C_i)\) 需要取到最大值,即 \(S\) 中 \(P_i-C_i\) 前 \(k\) 大的在 \(S'\) 中。
证毕。
令 \(S=\left\{1,2,\cdots,n\right\}\),试调整 \(S\) 使得其最小花费小于等于 \(m\)。考虑从 \(S\) 中删除一个元素 \(x\) 对于最小花费的贡献:
- \(x\notin S'\),则最小花费减小 \(P_x\)。
- \(x\in S'\),此时 \(x\) 被删除之后,满足 \(P_i-C_i\) 最大的 \(i(i\notin S')\) 被并入 \(S'\),则最小花费减小 \(C_x+P_i-C_i\)。
则要使 \(|S|\) 最大,则就要使每次选取对最小花费减小的贡献最大的 \(x\) 删除,即删除 \(\max_{x\notin S'}P_x\) 或 \(\max_{x\in S'}C_x\max_{i\notin S'}(P_i-C_i)\),直到最小花费小于等于 \(m\) 。
至于具体实现的话,可以考虑用 \(3\) 个优先队列来维护。
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#define MAXN 50005
using namespace std;
struct node0{
int p, c, id;
bool friend operator<(node0 a, node0 b){
return a.p - a.c < b.p - b.c;
}
}cow[MAXN];
struct node1{
int c, id;
bool friend operator<(node1 a, node1 b){
return a.c < b.c;
}
};
struct node2{
int p, c, id;
bool friend operator<(node2 a, node2 b){
return a.p < b.p;
}
};
int n, k, ans;
long long m, cost;
bool vis[MAXN];
priority_queue <node0, vector <node0>, less <node0>> q0;
priority_queue <node1, vector <node1>, less <node1>> q1;
priority_queue <node2, vector <node2>, less <node2>> q2;
int read(){
int t = 1, x = 0;char ch = getchar();
while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * t;
}
long long _read(){
long long t = 1, x = 0;char ch = getchar();
while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * t;
}
bool cmp(node0 a, node0 b){
return a.p - a.c > b.p - b.c;
}
int main(){
n = read();k = read();m = _read();
for(int i = 1 ; i <= n ; i ++)
cow[i].p = read(),cow[i].c = read();
for(int i = 1 ; i <= n ; i ++)cow[i].id = i;
ans = n;cost = 0;sort(cow + 1, cow + n + 1, cmp);
for(int i = 1 ; i <= k && i <= n ; i ++){
q1.push((node1){cow[i].c, cow[i].id});
cost += (long long)cow[i].c;
}
for(int i = k + 1 ; i <= n ; i ++){
q0.push((node0){cow[i].p, cow[i].c, cow[i].id});
q2.push((node2){cow[i].p, cow[i].c, cow[i].id});
cost += (long long)cow[i].p;
}
while(cost > m){
while(!q0.empty() && vis[q0.top().id] == true)q0.pop();
while(!q2.empty() && vis[q2.top().id] == true)q2.pop();
if(q0.empty() || q2.empty()){
node1 max = q1.top();q1.pop();
cost -= (long long)max.c;ans--;
}else{
node0 dmax = q0.top();
node1 cmax = q1.top();
node2 pmax = q2.top();
if(pmax.p > cmax.c + dmax.p - dmax.c){
cost -= (long long)pmax.p;ans--;
vis[pmax.id] = true;q2.pop();
}else{
cost -= (long long)(cmax.c + dmax.p - dmax.c);ans--;
vis[dmax.id] = true;q0.pop();q1.pop();
q1.push((node1){dmax.c, dmax.id});
}
}
}
cout << ans << endl;return 0;
}