分享每日一题之洛谷P8669 [蓝桥杯 2018 省 B] 乘积最大
提示:以下是本篇文章正文内容,下面案例可供参考
题意: 在 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;
}