题解【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;
}
posted @ 2024-05-26 11:21  2017BeiJiang  阅读(2)  评论(0编辑  收藏  举报