1. 程式人生 > 其它 >乘積最大

乘積最大

乘積最大

給定 $N$ 個整數 $A_{1},A_{2},…A_{N}$。

請你從中選出 $K$ 個數,使其乘積最大。

請你求出最大的乘積,由於乘積可能超出整型範圍,你只需輸出乘積除以 $1000000009$ 的餘數。

注意,如果 $X<0$, 我們定義 $X$ 除以 $1000000009$ 的餘數是負$\left( {−X} \right)$除以 $1000000009$ 的餘數,即:$0 - \left( {\left( {0 - x} \right)\% 100000009} \right)$

輸入格式

第一行包含兩個整數 $N$ 和 $K$。

以下 $N$ 行每行一個整數 $A_{i}$。

輸出格式

輸出一個整數,表示答案。

資料範圍

$1 \leq K \leq N \leq {10}^{5}$,
${−10}^{5} \leq A_{i} \leq {10}^{5}$

輸入樣例1:

5 3
-100000
-10000
2
100000
10000

輸出樣例1:

999100009

輸入樣例2:

5 3
-100000
-100000
-2
-100000
-100000

輸出樣例2:

-999999829

解題思路

  由於數中可能會有負數,為了儘可能得到正數,每次我們都成對選數。

  1. $k == n$,則全選。
  2. $k < n$:
    1. 如果$k$是偶數,結果必然可以取到非負,原因如下:
      1. 如果負數的個數是偶數個,那麼我們每次都成對去選,必然可以保證選的負數是偶數個,從而保證答案可以是非負的。
      2. 如果負數的個數是奇數個,由於$k < n$,我們一定可以把其中一個負數剔除掉,不選這個負數,那麼負數又變成偶數個,變成上一種情況,保證答案可以是非負的。
    2. 如果$k$是奇數:
      1. 如果全部數都是負數,結果必然小於$0$。
      2. 如果至少存在一個數是非負的,那麼我們先選擇其中一個非負的數,那麼就變成了從$n - 1$個數中選$k - 1$個數,同時$k - 1$是偶數,又變成了上面第一類的情況,從而保證答案可以是非負的。

  AC程式碼如下:

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 typedef long long
LL; 8 9 const int N = 1e5 + 10, mod = 1e9 + 9; 10 11 int a[N]; 12 13 int main() { 14 int n, m; 15 scanf("%d %d", &n, &m); 16 for (int i = 0; i < n; i++) { 17 scanf("%d", a + i); 18 } 19 20 sort(a, a + n); 21 22 int ret = 1, i = 0, j = n - 1, sign = 1; 23 if (m & 1) { // 如果k是奇數 24 ret = a[j--]; // 先選擇最右邊的那個數 25 if (ret < 0) sign = -1; // 如果最右邊的數是負數,意味著全部數都是負數 26 m--; 27 } 28 29 while (m) { 30 LL left = (LL)a[i] * a[i + 1], right = (LL)a[j] * a[j - 1]; // 每次成對選數 31 32 // 選擇最左最右乘積最大的一對數。其中如果所有數是負數,那麼應該選擇最右邊的那對 33 if (left * sign > right * sign) { 34 ret = left % mod * ret % mod; 35 i += 2; 36 } 37 else { 38 ret = right % mod * ret % mod; 39 j -= 2; 40 } 41 m -= 2; 42 } 43 44 printf("%d", ret); 45 46 return 0; 47 }

參考資料

  AcWing 1239. 乘積最大(藍橋杯C++ AB組輔導課):https://www.acwing.com/video/735/