题目
算法思路
- 对商品进行排序,截至日期小的排在前面,相同日期,价值大的排在前面
- 如果在当前天数now之前,则直接选择
- 我们把已经选择了的物品,丢入小根堆中维护
- 如果==now,则我们跟小根堆的top比较大小,如果价值大于它,堆顶pop,把第i个物品丢入小根堆,因为那一天,第i个物品必然还未截至,我们可以不买原本计划买的那个物品,直接选取买第i个物品(显然这是一种正确的策略)
代码实现
/*
日期截止日期背包
贪心策略,加堆
先选择,然后替换掉原来的决策
*/
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
#define el '\n'
#define cl putchar('\n')
#define eb emplace_back
#define fir first
#define sec second
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vci;
typedef map<int,int> mii;
typedef mii::iterator mii_it;
const int N=1e5+10;
int T,n,m,x,y,k;
pii a[N];
bool cmp(pii a1,pii a2) {//截至日期小的排在前面,相同日期,价值大的排在前面
return a1.second<a2.second||(a1.second==a2.sec&&a1.first>a2.first);
}
int main() {
cin.tie(0);
cout.tie(0);
cin.sync_with_stdio(false);
cin>>T;
while(T--) {
ll ans=0;
priority_queue <int ,vector<int>,greater<int> > q;//小顶堆
cin>>n;
for(int i=1; i<=n; i++) {//输入价值
cin>>a[i].first;
}
for(int i=1; i<=n; i++) {//输入截至日期
cin>>a[i].sec;
}
sort(a+1,a+n+1,cmp);//排序
int now=0;
for(int i=1; i<=n; i++) {
if(now<a[i].sec) {//如果在时限内,则直接选择
now++;
ans+=a[i].fir;
q.push(a[i].fir);//扔进堆中
} else if(now==a[i].sec) {//已经选满了,则从堆中替换掉
//因为那一天,第i个物品必然还未截至,我们可以不买原本计划买的那个物品,直接选取买第i个物品
if(!q.empty()&&q.top()<a[i].fir) {
ans+=a[i].fir-q.top();//替换掉那天的值,无需关心是哪一天
q.pop();
q.push(a[i].first);
}
}
}
cout<<ans<<el;
}
}