牛客2020寒假训练营2-F

牛客2020寒假训练营2-F

七月 15, 2020

F.拿物品

题意
有n个数每个数 ai bi两个属性
两人轮流拿 A先
A最后获得的分数为 他拿到的所有物品中ai的和
B最后获得的分数为 他拿到的所有物品中bi的和
两人都想比对方分高问两者怎么拿输出他们拿到的物品

题解

​假设物品已经被选完,此时 牛牛选择的物品 A 属性的价值和是 N , 牛可乐选择的物品 B 属性价值和是 M 。 如果 牛牛的 (a1,b1)物品与 牛可乐的 (a2,b2)( 交换,则 N′=N−a1+a2,M′=M+b1−b2 ,对于 牛牛(目标是最大化 N−M )来说会变得更优仅当 a1+b1<a2+b2 ( N′−M′>N−M化简就能得到),对于 牛可乐也一样。所以两人都会优先选择 ai+bi 最大的物品。 将物品按照两个属性的和从大到小排序,依次分给两人即可。 除排序时间复杂度 O(n) 。

突破口从最后两者取到的价值交换后取得最优解的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# include<bits/stdc++.h>

using namespace std;

# define endl '\n'

struct Data{
int a,b;
int pos;
}data[(int)2e5+5];
bool vis[(int)2e5+5];
bool cmp(Data x,Data y){return x.a+x.b>y.a+y.b;}
int main(){
int n;cin>>n;int cnt=0;
for(int i=0;i<n;i++)cin>>data[i].a,data[i].pos=i+1;
for(int i=0;i<n;i++)cin>>data[i].b;
sort(data,data+n,cmp);
vector<int>ans1,ans2;
bool turn=1;
for(int i=0;i<n;i++){
if(turn)ans1.push_back(data[i].pos);
else ans2.push_back(data[i].pos);
turn=!turn;
}
int len1=ans1.size(),len2=ans2.size();
for(int i=0;i<len1;i++)cout<<ans1[i]<<" ";
cout<<endl;
for(int i=0;i<len2;i++)cout<<ans2[i]<<" ";
}