Codeforces798D Mike and distribution

本文详细解析 CodeForces 798D 的解题思路及算法实现,通过数学分析和贪心策略确定选择元素数量与序列,确保所选序列的总和大于未选元素总和,适用于奇数和偶数长度序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

  http://codeforces.com/problemset/problem/798/D

题解

  这题啊,亦可赛艇。
  做这道题要首先注意到两个事实:
  一、所有数都是正数;
  二、答案一定是恰好选择 n2+1 个。
  因为如果存在一种选择小于 n2+1 的答案,那么我多选几组数字肯定依然合法。
  因为有两个序列不好搞,先给第一个序列排个序。
  当 n 为奇数时,如果我选择了第一组,那么后面的n1组数要选出 n2 组,那么可以采取相邻的两组数选择一个的策略。这样可以保证无论怎样选, a 序列都满足选择的数比不选择的数的和大。同时我们可以对b序列贪心,相邻两个选择 b 比较大的,这样肯定是符合要求的,自己写写画画就能看出。以上讨论的是我强制选择第一组,下面考虑我强制不选择第一组。这时就要在后面n1组数里,选择 n2+1 组,使得满足题目要求。考虑先选择 n2 组,这样无论怎么选, a 序列就已经不可能满足要求,b序列如果还按照之前的贪心策略选择,那么它是否满足要求还不得而知,假设我们已经这么做了,现在要利用最后一次选择的机会使得我选的序列合法。如果继续考虑第一组数强制不选,那么任意选择后面的哪个数字,我们都不好证明它是否满足要求。这时我们尝试着去选择第一组数字,那么 a 序列肯定满足要求了,看下b序列,因为我采取了贪心策略,所以不考虑第一组的话,选择数字的和已经不小于不选择的数字的和,现在我选择了第一组,相当于给选的的数字的和加了一个正数,所以 b 序列也满足要求了。
  对于n为偶数的情况,同样先选 n2 个,采取之前的县排序后贪心地策略,那么这时两个序列都已经满足,选的数字的和不小于没选的数字的和,我再任意选一个,就行了。(我程序中是直接强制选前两个,然后对后面的再执行贪心)

代码

//数学、贪心 
#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
int N, cho[maxn];
struct num{int a, b, id;}n[maxn];
bool operator<(const num &x, const num &y){return x.a>y.a;}
int main()
{
    int i, j;
    scanf("%d",&N);
    for(i=1;i<=N;i++)scanf("%d",&n[i].a);
    for(i=1;i<=N;i++)scanf("%d",&n[i].b);
    for(i=1;i<=N;i++)n[i].id=i;
    sort(n+1,n+N+1);
    if(N&1)
    {
        cho[n[1].id]=1;
        for(i=2;i<=N;i+=2)
        {
            if(n[i].b>n[i+1].b)cho[n[i].id]=1;
            else cho[n[i+1].id]=1;
        }
    }
    else
    {
        cho[n[1].id]=cho[n[2].id]=1;
        for(i=3;i<=N;i+=2)
        {
            if(n[i].b>n[i+1].b)cho[n[i].id]=1;
            else cho[n[i+1].id]=1;
        }
    }
    printf("%d\n",N/2+1);
    for(i=1;i<=N;i++)if(cho[i])printf("%d ",i);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值