贪心之P8669 [蓝桥杯 2018 省 B] 乘积最大

文章目录

  • 前言
  • 一、例题
  • 二、题目分析
  • 三、代码解答


前言

分享每日一题之洛谷P8669 [蓝桥杯 2018 省 B] 乘积最大


提示:以下是本篇文章正文内容,下面案例可供参考

一、例题

贪心之P8669 [蓝桥杯 2018 省 B] 乘积最大_第1张图片

二、题目分析

题意: 在 N 个数中取 K 个数,使这 K 个数的乘积最大,答案对 1000000009 取模

看到这题,首先想到贪心,第一是因为要求乘积最大,第二是因为数据不是特别大,遇到求一个极值的东西可以想想贪心,但也要结合题意和数据范围来具体判断到底用哪些算法

那么我们用贪心来解决这道题,首先肯定是用数组存储并且从小到大排好序,
其次我们分析,当两个数符号相同时,必定为正数,此时既然我们排好序了,我们就分别从左和右两端两两取值去比较,谁更合适即可,这里并不是说此时左右分别两两取的两个值都是相同符号,只是大概率是,而且左端两个值相乘并不一定比右端两值相乘小,比如 -1000*(-999) 和 3*4

但此时我们又会发现一个问题,两个两个的去取值,如果要求我们取的总数k为奇数怎么办?
我们这里直接特判,如果是奇数,我们先把数组中最大的那个值取出来即可,但是!!! 这个最大值可能为负数,所以我们又要进行判断一下,你仔细想想,如果这个值为负数,后续在判断左侧两值相乘和右侧两值相乘的时候,是选小的还是大的值呢?
答案当然是选小的啦!

思路: 先把这 N 个数从小到大排序,若 K 为奇数则先乘上最大的一个并把 K−1。若最大的数为负数则记录 f=−1,用贪心从两侧取数并比较与 f 之积,进而求解

三、代码解答

#include 
#include 
using namespace std;
const long long mod = 1e9 + 9;
int n, k;
long long arr[100005];
long long sum = 1;
int f = 1; // 记录最大的数是否为负数
int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> arr[i];
    }
    sort(arr + 1, arr + 1 + n); // 从小到大排好

    long long left = 1;
    long long right = n;
    if (k % 2 == 1)
    {
        sum *= arr[n]; // 先把最大的取了
        sum %= mod;
        right--;
        k--;
        if (sum < 0)
            f = -1;
    }

    while (k != 0) // 每次选两个
    {
        long long t1 = (arr[right] * arr[right - 1]);
        long long t2 = (arr[left] * arr[left + 1]);
        if (t2 * f >= t1 * f)
        {
            sum *= t2 % mod;
            sum %= mod;
            left += 2;
        }
        else
        {
            sum *= t1 % mod;
            sum %= mod;
            right -= 2;
        }
        k -= 2;
    }
    cout << sum % mod;
    return 0;
}

你可能感兴趣的:(刷题小记,蓝桥杯,贪心算法,c++)