y总的思路
摘自题解 乘积最大
换一种思路思考
当k < n且为偶数时,数组中负数的个数可以分为奇数和偶数个两种情况:
1.如若负数的个数是偶数个,那么每两个数可以组合成一个新的数,所要求的答案是最大数,就可以让原数组
每两个数相乘组合成一个新的全为正的数组(如果n为奇数则让一个单独的正数为一个不参与两两相乘),然后
从中选取k / 2个数,所以此时答案一定为非负数。
2.如果负数的个数是奇数个,那么也可以向上面一样两两相组合,只不过一定会变成若干个正数带一个负数的
情况,此时依旧是选取k / 2个数,当不选这唯一的负数的时候答案一定也是非负的,如果一定要求我们把这个
负数也选上,显然等于我们需要选上所有的数,此时不满足k < n的情况所以可以忽略,此时一定也是非负数。
k < n且为奇数的时候,因为此时k / 2不是一个整数,所以可以考虑把他转化为上面的情况,即转化为选偶数
个数,只要先选上一个数即可,在从剩下的数中选取k - 1(偶数)个数。因为选偶数个数一定是非负数,只有乘
一个非负数才不会变号,所以第一下选的最大的那个数决定了我们的答案是否正负,如果最大的数是负数那么
答案为负,此时则在比较大小的时候需要选乘积为正但是较小的数,因为答案一定为负所以越小越大。
一个坑点
因为数组中的值最大可以取到1e5,所以两个数相乘可以取到1e10,在乘上res % MOD的最大值1e9就会爆
long long(1e19),所以需要先将相乘得到的数 % MOD得到一个1e9以内的数,这样乘上res最大1e18不会爆。
res = x % MOD * res % MOD; // 不会爆 先处理x
res = res % mod * x % mod; // 会爆 因为res就是%MOD后得到的结果 所以先处理res并没有效果
// 上面本质还是res * x后在取余 而没有先处理防止爆long long
代码
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, MOD = 1000000009;
int n, k, a[N], res = 1;
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> a[i];
sort(a, a + n);
int l = 0, r = n - 1, sign = 1;
if (k % 2)
{
res = a[r--];
k--;
if (res < 0)
sign = -1;
}
while (k)
{
LL x = (LL)a[l] * a[l + 1], y = (LL)a[r] * a[r - 1];
if (x * sign > y * sign)
{
res = x % MOD * res % MOD;
// res = (res * (x % MOD)) % MOD;
l += 2;
}
else
{
res = y % MOD * res % MOD;
r -= 2;
}
k -= 2;
}
return cout << res, 0;
}
总结
y总的思路很简明但是我自己看的时候不是一下就能想明白,就自己换了个法子想了想,但是有点马后炮的味道。
如果有不合理的地方还望指出改正或者删掉错误思路
这个题在y总那个视频里面 怎么没有找到
铁子哥,我有点理不清为什么要两边两个两个来比较,求求