UVa 10747 Maximum Subsequence

9 篇文章 1 订阅

分类讨论加贪心解题。

1 1 1)读入数据,将其存放到数组 A A A 中,复制数组 A A A 的所有元素到数组 B B B 中。

2 2 2)将数组 A A A 的元素按绝对值大小递减排序,数组 B B B 的元素按大小递增排序。

3 3 3)将数组 A A A 中前 K K K 个数按正数、负数、零进行分类,令正数的个数为 P P P,负数的个数为 D D D,零的个数为 Z Z Z,然后分类讨论。

4 4 4)若 Z > 0 Z > 0 Z>0,即有零元素,显然最大乘积为零,统计数组 B B B 中后 K K K 个元素之和即可。

5 5 5)若 Z = = 0 Z == 0 Z==0 D = = 0 D == 0 D==0,即绝对值较大的 K K K 个数全为正数,统计数组 B B B 中后 K K K 个元素之和即可。

6 6 6)若 Z = = 0 Z == 0 Z==0 P = = 0 P == 0 P==0,由于奇数个负数的积仍为负数,需要根据 K K K 的奇偶性进行选择。

6.1 6.1 6.1)若 K K K 为偶数,则前 K K K 个负数的积为正数,此时统计数组 B B B 的前 K K K 个元素之和即可。

6.2 6.2 6.2)若 K K K 为奇数,分两种情况:

6.2.1 6.2.1 6.2.1) 如果数组 A A A 中除了前 K K K 个元素外没有正数,那么最大积要么为零,要么为负数,则取数组 B B B 的后 K K K 个元素相乘能够得到最大的积且同时和最大;

6.2.2 6.2.2 6.2.2)如果数组 A A A 中除了前 K K K 个元素外还有正数,则取绝对值最大的正数替换掉第 K K K 个负数,则可保证积为正,此时取数组 A A A 中的前 K − 1 K - 1 K1 个负数加上数组 B B B 的最后一个元素相乘能够得到最大的积且同时和最大;

7 7 7)若 Z = = 0 Z == 0 Z==0 P > 0 P > 0 P>0 D > 0 D > 0 D>0,根据 D D D 的奇偶性进行选择。

7.1 7.1 7.1)若 D D D 为偶数,则偶数个负数的积为正数,将数组 A A A 中前 K K K 个元素相乘能够得到最大的积且同时和最大;

7.2 7.2 7.2)若 D D D 为奇数,则考虑将一个正数替换为负数,或将一个负数替换为正数,这样能够保证负数的数量为偶数,从而能够得到正的积。此时从数组 A A A 中的第 K + 1 K + 1 K+1 个元素开始,寻找绝对值最大的一个正数和绝对值最大的一个负数,令其分别为 P B PB PB N B NB NB,此时有以下几种情形:

7.2.1 7.2.1 7.2.1 P B PB PB N B NB NB 均不存在,表明数组 A A A 中除了前 K K K 个元素外要么全为 0 0 0,要么 K = = N K == N K==N,此时,将数组 B B B 中后 K K K 个元素相乘能够得到最大的积且同时和最大。

7.2.2 7.2.2 7.2.2 P B PB PB 存在, N B NB NB 不存在,将 P B PB PB 替换数组 A A A 中前 K K K 个元素中绝对值最小的那个负数即可。

7.2.3 7.2.3 7.2.3 P B PB PB 不存在, N B NB NB 存在,将 N B NB NB 替换数组 A A A 中前 K K K 个元素中绝对值最小的那个正数即可。

7.2.4 7.2.4 7.2.4 P B PB PB N B NB NB 均存在,令数组 A A A 中前 K K K 个元素中绝对值最小的正数为 P S PS PS,绝对值最小的负数为 N S NS NS,若 P B × P S > = N B × N S PB \times PS >= NB \times NS PB×PS>=NB×NS,则将 P B PB PB 替换 N S NS NS,否则将 N B NB NB 替换 P S PS PS

// Maximum Subsequence
// UVa ID: 10747
// Verdict: Accepted
// Submission Date: 2021-11-12
// UVa Run Time: 0.020s
//
// 版权所有(C)2021,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>

using namespace std;

int ai[10010], bi[10010], positive[10010], negative[10010], pc, nc, zero, N, K;

void sumFirstK()
{
    cout << accumulate(bi, bi + K, 0) << '\n';
}

void sumLastK()
{
    cout << accumulate(bi + N - K, bi + N, 0) << '\n';
}

int sumAll()
{
    int sum = accumulate(positive, positive + pc, 0);
    sum += accumulate(negative, negative + nc, 0);
    return sum;
}

bool cmp(int a, int b)
{
    if (abs(a) != abs(b)) return abs(a) > abs(b);
    return a > b;
}

int main(int argc, char *argv[])
{    
    cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);

    while (cin >> N >> K)
    {
        if (N == 0) break;
        for (int i = 0; i < N; i++) { cin >> ai[i]; bi[i] = ai[i]; }
        sort(ai, ai + N, cmp);
        sort(bi, bi + N);
        pc = nc = zero = 0;
        for (int i = 0; i < K; i++)
        {
            if (ai[i] == 0) { zero = 1; break; }
            if (ai[i] > 0) positive[pc++] = ai[i];
            else negative[nc++] = ai[i];
        }
        if (zero || !nc) { sumLastK(); continue; }
        if (!pc)
        {
            if (K % 2 == 0) sumFirstK();
            else
            {
                if (bi[N - 1] <= 0) sumLastK();
                else
                {
                    int sum = accumulate(ai, ai + K - 1, 0) + bi[N - 1];
                    cout << sum << '\n';
                }
            }
        }
        else
        {
            if (nc % 2 == 0) cout << sumAll() << '\n';
            else
            {
                int pb, nb, pflag = 0, nflag = 0;
                for (int i = K; i < N && (!pflag || !nflag); i++)
                {
                    if (ai[i] > 0 && !pflag)
                    {
                        pflag = 1;
                        pb = ai[i];
                    }
                    if (ai[i] < 0 && !nflag)
                    {
                        nflag = 1;
                        nb = ai[i];
                    }
                }
                
                if (pflag && nflag)
                {
                    if (positive[pc - 1] * pb >= negative[nc - 1] * nb)
                    {
                        int sum = sumAll() - negative[nc - 1] + pb;
                        cout << sum << '\n';
                    }
                    else
                    {
                        int sum = sumAll() - positive[pc - 1] + nb;
                        cout << sum << '\n';
                    }
                }
                else if (pflag)
                {
                    int sum = sumAll() - negative[nc - 1] + pb;
                    cout << sum << '\n';
                }
                else if (nflag)
                {
                    int sum = sumAll() - positive[pc - 1] + nb;
                    cout << sum << '\n';
                }
                else sumLastK();
            }
        }
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值