题解:CF1969D Shop Game
对于 Bob
B 的每次零元购相当于吞掉了 A 本应获得的
考虑当 A 选出商品后花的钱
对于 Alice
买少于或等于
选出的物品中,
枚举拿出去投喂 B 的商品和正常赚钱的商品的分界线。
在分界线左侧,当然是希望净亏的越少越好,所以选择的一定是
在分界线右侧,凡是
得到每次左侧的最小花费和右侧的最大利润之后,两者结合即可计算出此时实际利润。对所有的分界线算出来再取最大值就是 A 在 B 采取最优策略下所能得到的最大利润。
这个最大利润可能仍然是负数。这个时候不如不取,还需处理一下。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int n,k;
pair<int,int> money[N];
long long sum_rev[N];
priority_queue<int> sorry;
bool cmp(pair<int,int> x,pair<int,int> y)
{
return x.second>y.second;
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&money[i].first);
for(int i=1;i<=n;i++) scanf("%d",&money[i].second);
sort(money+1,money+n+1,cmp);
for(int i=n;i>=1;i--)
sum_rev[i]=sum_rev[i+1]+max(money[i].second-money[i].first,0);
long long oh_no=0;
for(int i=1;i<=k;i++)
{
sorry.push(money[i].first);
oh_no+=money[i].first;
}
long long ans=0;
for(int i=k+1;i<=n;i++)
{
ans=max(ans,sum_rev[i]-oh_no);
if(sorry.empty()) continue;
if(money[i].first<sorry.top())
{
oh_no-=sorry.top(); sorry.pop();
oh_no+=money[i].first; sorry.push(money[i].first);
}
}
printf("%lld\n",ans);
for(int i=1;i<=n;i++) sum_rev[i]=0;
while(!sorry.empty()) sorry.pop();
}
return 0;
}