题解【CF798D Mike and distribution】
思考方向:构造方法满足 \(A\) 的要求,再满足 \(B\) 的要求。
如果只考虑 \(A\),有一种显然的方案:将 \(A\) 从大到小排序,选出前 \(\left \lfloor \frac{n}{2} \right \rfloor+1\) 大的即可。但这样显然难以扩展,所以需要另寻方案。
由于题目提供了额外的 \(+1\),所以先将最大的 \(A_1\) 选上,对于剩下的 \(A_2\sim A_n\),由于要满足二倍关系,不妨进行两两分组,即 \(A_2,A_3\) 一组,\(A_4,A_5\) 一组,依次类推。
这样会有一个结论:一组内任意选一个即可满足题目要求。
证明:
最坏的情况是,每组都选小的那个,即 \(A_3,A_5,A_7...\),那么最终总和(此处将选的数加上,不选的数减去,如果最终总和 \(>0\),则说明满足题目条件)为:\(A_1-A_2+A_3-A_4+A_5...-A_{n-1}+A_n\),但是 \(A_1>A_2,A_3>A_4...\),所以最后总和 \(>0\),满足条件。
所以对于 \(A\) 的每一组内,只需要在 \(B\) 的对应下标选出比较大的数(反正 \(A\) 怎么选都行),一直下去就可以得出答案。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
struct node {
int a,b,id;
}s[N];
int cmp(node x,node y) {
if(x.a!=y.a) return x.a>y.a;
else return x.b>y.b;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) {
cin>>s[i].a;
s[i].id=i;
}
for(int i=1;i<=n;i++) cin>>s[i].b;
sort(s+1,s+1+n,cmp);
int st=0;
vector<int> ans;
if(n%2==0) {
st=3;
ans.push_back(s[1].id); ans.push_back(s[2].id);
}
else {
st=2;
ans.push_back(s[1].id);
}
for(;st<=n;st+=2) {
if(s[st].b>s[st+1].b) ans.push_back(s[st].id);
else ans.push_back(s[st+1].id);
}
sort(ans.begin(),ans.end());
cout<<ans.size()<<endl;
for(int a:ans) cout<<a<<" ";
return 0;
}