专栏文章
题解:P12360 [eJOI 2024] 足球决斗 / CF Duels
P12360题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minpg178
- 此快照首次捕获于
- 2025/12/02 06:12 3 个月前
- 此快照最后确认于
- 2025/12/02 06:12 3 个月前
首先,答案是可二分的,如果检查了前 个足球馆即能保证必胜,那么多检查几个仍能确保必胜。
考虑如何检查答案的可行性。
能确保必胜,当且仅当在最坏情况下仍然能够取胜。
对于本题而言,最坏情况就是敌队经理足够明智,采取了最优策略。换位思考一下,他一定把战斗力高的放在奖金高的体育馆,这样赢得奖金最高的比赛的胜算最大。简单证明一下,若他没有这样做,放弃了最高奖金的比赛,那么这名球员至多赢得另一场比赛的奖金,必然无法造成最优的贡献。
也就是说,在后面的没有确定的比赛中,敌队经理会按照比赛场馆奖金从高到低的顺序,依次放入手头上最强的球员,次强的,依此类推。
于是,最坏情况下敌方球员排布已经得知。思考我方如何应对。
我们按照奖金从高到低的顺序考虑,如果我方手上有能够击败对方的球员,那么一定要出动这名球员,理由和刚才一样,如果放弃了这场比赛,那么他只能获得一场更低奖金的比赛,不优。
具体地,将每场比赛按照奖金从高到低遍历,找到战力高于对方且战力最低的球员,即以最小损耗获得奖金,若没有高于对方的球员,即放弃奖金。
实现方面使用 multiset 比较好。
AC 代码:
CPP#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+50;
int T,n;
int a[N],b[N],p[N];
int L,R,mid,res,sma,smb;
multiset<int>s;
multiset<int>::iterator it;
struct node{
int p;
int b;
}tmp[N];
int tb[N];
bool cmp(node x,node y){
return x.p<y.p;
}
bool cmp2(node x,node y){
return x.p>y.p;
}
bool check(int x){
s.clear();
sma=0;
smb=0;
for(int i=1;i<=x;i++){
tmp[i].b=b[i];
tmp[i].p=p[i];
}
for(int i=x+1;i<=n;i++) tmp[i].p=p[i];
sort(tmp+x+1,tmp+n+1,cmp);
for(int i=x+1;i<=n;i++) tb[i]=b[i];
sort(tb+x+1,tb+n+1);
for(int i=x+1;i<=n;i++) tmp[i].b=tb[i];
sort(tmp+1,tmp+n+1,cmp2);
for(int i=1;i<=n;i++) s.insert(a[i]);
for(int i=1;i<=n;i++){
it=s.upper_bound(tmp[i].b);
if(it==s.end()){
smb+=tmp[i].p;
it=s.lower_bound(0);
s.erase(it);
continue;
}
sma+=tmp[i].p;
s.erase(it);
}
return sma>smb;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
L=0;
R=n;
res=-1;
while(L<=R){
mid=(L+R)>>1;
if(check(mid)){
R=mid-1;
res=mid;
}else L=mid+1;
}
cout<<res<<'\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...