Problem:
Score : 500 points

Problem Statement

Given are N integers A_1,\ldots,A_N.

We will choose exactly K of these elements. Find the maximum possible product of the chosen elements.

Then, print the maximum product modulo (10^9+7), using an integer between 0 and 10^9+6 (inclusive).

Constraints

1 \leq K \leq N \leq 2\times 10^5

|A_i| \leq 10^9

Input

Input is given from Standard Input in the following format:

N K
A_1 \ldots A_N

Output

Print the maximum product modulo (10^9+7), using an integer between 0 and 10^9+6 (inclusive).

Sample Input 1

4 2
1 2 -3 -4

Sample Output 1

12

The possible products of the two chosen elements are 2, -3, -4, -6, -8, and 12, so the maximum product is 12.

Sample Input 2

4 3
-1 -2 -3 -4

Sample Output 2

1000000001

The possible products of the three chosen elements are -24, -12, -8, and -6, so the maximum product is -6.

We print this value modulo (10^9+7), that is, 1000000001.

Sample Input 3

2 1
-1 1000000000

Sample Output 3

1000000000

The possible products of the one chosen element are -1 and 1000000000, so the maximum product is 1000000000.

Sample Input 4

10 10
1000000000 100000000 10000000 1000000 100000 10000 1000 100 10 1

Sample Output 4

999983200

Be sure to print the product modulo (10^9+7).

Solution in Rust (1.42.0) (judge verdict: Runtime Error)

#![allow(unused_imports)]
#![allow(clippy::many_single_char_names)]

// language: Rust(1.42.0)
// check available crates on AtCoder at "https://atcoder.jp/contests/language-test-202001"
// My Library Repo' is at "https://github.com/Loptall/prcn_lib"

/*
    そう甘くはないんだな〜w
*/

// from std...
use std::cmp::{
    max, min, Ordering,
    Ordering::{Equal, Greater, Less},
    Reverse,
};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::convert::TryInto;
use std::mem::swap;
use std::num::{NonZeroU32, ParseIntError};
use std::ops::{
    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
    Index, IndexMut, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
    SubAssign,
};
use std::process::exit;
use std::{f32, f64, i128, i16, i32, i64, i8, isize, u128, u16, u32, u64, u8, usize};

// Dep' crates are...
use itertools::*;
use itertools_num::*;
use lazy_static::lazy_static;
use maplit::{btreemap, btreeset, hashmap, hashset};
use num_bigint::{BigInt, BigUint};
use num_complex::Complex;
use num_integer::{binomial, gcd, lcm, multinomial, Integer};
use num_rational::Rational;
use num_traits::{clamp, one, pow, zero, Num, NumAssignOps, NumOps, One, Pow, Zero};
use permutohedron::Heap;
use proconio::{
    fastout, input, is_stdin_empty,
    marker::{Bytes, Chars, Isize1, Usize1},
};
use rand::random;

pub const MOD10E9_7: i64 = 1000000007;
pub const MOD99_: usize = 998244353;
pub const MAX: usize = std::usize::MAX;
pub const PI: f64 = f64::consts::PI;
pub const A: u8 = 65;

// code...
// #[fastout]
fn main() {
    input! {
        n: usize, k: usize,
        mut a: [i64; n]
    }

    a.sort_by_key(|x| x.abs());

    if k == n {
        let mut i = 1;
        for e in a {
            i *= e;
            // dbg!(i);
            i %= MOD10E9_7;
        }
        if i < 0 {
            i += MOD10E9_7;
        }
        println!("{}", i);
    } else if a.iter().all(|x| *x < 0) && k.is_odd() {
        let mut i = 1;
        for e in a.into_iter().take(k) {
            i *= e;
            i %= MOD10E9_7;
        }
        if i < 0 {
            i += MOD10E9_7;
        }
        println!("{}", i);
    } else {
        let mut i = 1;
        let mut used = HashSet::new();
        for e in a.iter().rev().take(k) {
            used.insert(e);
            i *= e;
            // dbg!(i);
            i %= MOD10E9_7;
        }

        if i >= 0 {
            println!("{}", i);
        } else {
            let p = {
                let x = a.iter().find(|z| used.contains(*z) && **z >= 0).unwrap();
                let y = a.iter().rfind(|z| !used.contains(*z) && **z < 0).unwrap();
                i / x * y
            };
            let q = {
                let x = a.iter().rfind(|z| !used.contains(*z) && **z >= 0).unwrap();
                let y = a.iter().find(|z| used.contains(*z) && **z < 0).unwrap();
                i / y * x
            };

            println!("{}", max(p, q) % MOD10E9_7);
        }
    }
}

/// n % m
/// ただし答えが負になる場合は余分にmを足すことで一意な値を保証
///
/// # Panic
/// 異なるmod間での演算をattemptした時
fn compensated_rem(n: i64, m: usize) -> i64 {
    match n % m as i64 {
        r if r >= 0 => r,
        r => r + m as i64,
    }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Modulo {
    Static(NonZeroU32),
    Dynamic,
}
impl Modulo {
    pub fn get(&self) -> Option<u32> {
        match self {
            Modulo::Static(nz) => Some(nz.get()),
            Modulo::Dynamic => None,
        }
    }
}
/// `ModInt -> PrimiteveInt` への暗黙のキャストは行わない!
/// (get関数を提供するのでそれ使ってどうぞ)
///
/// `PrimitiveInt -> ModInt` は許可する
#[derive(Debug, Clone, Copy)]
pub struct ModInt {
    num: i64,
    _modulo: Modulo,
}
impl Into<usize> for ModInt {
    fn into(self) -> usize {
        self.get() as usize
    }
}
pub trait IntoModInt: Copy {
    fn to_mint<M: TryInto<u32> + Copy>(self, modulo: M) -> ModInt;
}
macro_rules ! impl_into_mint {($ ($ t : ty ) ,* ) => {$ (impl IntoModInt for $ t {fn to_mint < M : TryInto < u32 > + Copy > (self , modulo : M ) -> ModInt {ModInt :: new (self , modulo ) } } ) * } ; }
impl_into_mint!(usize, u8, u16, u32, u64, isize, i8, i16, i32, i64);
impl PartialEq for ModInt {
    fn eq(&self, other: &Self) -> bool {
        if !check_mod_eq(self, other).1 {
            panic!("cannot compare these values because they have different modulo number")
        }
        self.get() == other.num
    }
}
impl PartialOrd for ModInt {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if !check_mod_eq(self, other).1 {
            None
        } else {
            Some(self.get().cmp(&other.num))
        }
    }
}
fn check_mod_eq(a: &ModInt, b: &ModInt) -> (NonZeroU32, bool) {
    match (a._modulo, b._modulo) {
        (Modulo::Static(a), Modulo::Static(b)) => {
            if a == b {
                (a, true)
            } else {
                (unsafe { NonZeroU32::new_unchecked(1) }, false)
            }
        }
        (Modulo::Static(m), Modulo::Dynamic) | (Modulo::Dynamic, Modulo::Static(m)) => (m, true),
        (Modulo::Dynamic, Modulo::Dynamic) => (unsafe { NonZeroU32::new_unchecked(1) }, false),
    }
}
impl ModInt {
    /// always `_modulo > num >= 0 && _modulo >= 1`
    pub fn new<N: TryInto<i64>, M: TryInto<u32> + Copy>(n: N, m: M) -> Self {
        let m = NonZeroU32::new(m.try_into().ok().expect("modulo number may be wrong")).unwrap();
        let r = n
            .try_into()
            .ok()
            .expect("modulo number maybe over i64 range");
        let num = compensated_rem(r, m.get() as usize);
        Self {
            num,
            _modulo: Modulo::Static(m),
        }
    }
    /// get inner value
    pub fn get(&self) -> i64 {
        self.num
    }
    /// mod of modint
    ///
    /// # Panic
    /// if variant is Modulo::Dynamic
    pub fn get_mod(&self) -> usize {
        self._modulo.get().unwrap() as usize
    }
    /// return the power of self with mod, using binary powering method
    /// cannot use of Dynamic type mod Self
    pub fn pow_mod(&self, mut exp: usize) -> Self {
        let mut res = 1;
        let mut base = self.get() as usize;
        let m = self.get_mod();
        while exp > 0 {
            if exp & 1 != 0 {
                res *= base;
                res %= m;
            }
            base *= base;
            base %= m;
            exp >>= 1;
        }
        Self::new(res, self.get_mod())
    }
    /// `a / b == a * b^(-1)` となる `b^(-1)` を求める
    pub fn inv(&self) -> i64 {
        let x = self.get().extended_gcd(&(self.get_mod() as i64)).x;
        compensated_rem(x, self.get_mod())
    }
}
impl Add<Self> for ModInt {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        let c = check_mod_eq(&self, &rhs);
        if !c.1 {
            panic!("modulo between two instance is different!")
        }
        let r = self.get() + rhs.num;
        Self {
            num: if r >= self.get_mod() as i64 {
                r - c.0.get() as i64
            } else {
                r
            },
            _modulo: Modulo::Static(c.0),
        }
    }
}
impl AddAssign<Self> for ModInt {
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs;
    }
}
impl Sub<Self> for ModInt {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        let c = check_mod_eq(&self, &rhs);
        if !c.1 {
            panic!("modulo between two instance is different!")
        }
        let num = compensated_rem(self.get() - rhs.get(), c.0.get() as usize);
        Self {
            num,
            _modulo: Modulo::Static(c.0),
        }
    }
}
impl SubAssign<Self> for ModInt {
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}
impl Mul<Self> for ModInt {
    type Output = Self;
    fn mul(self, rhs: Self) -> Self::Output {
        let c = check_mod_eq(&self, &rhs);
        if !c.1 {
            panic!("modulo between two instance is different!")
        }
        let num = compensated_rem(self.get() * rhs.get(), c.0.get() as usize);
        Self {
            num,
            _modulo: Modulo::Static(c.0),
        }
    }
}
impl MulAssign<Self> for ModInt {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs
    }
}
impl Div<Self> for ModInt {
    type Output = Self;
    fn div(self, rhs: Self) -> Self::Output {
        let c = check_mod_eq(&self, &rhs);
        if !c.1 {
            panic!("modulo between two instance is different!")
        }
        Self {
            num: self.get() * rhs.inv() % c.0.get() as i64,
            _modulo: Modulo::Static(c.0),
        }
    }
}
impl DivAssign<Self> for ModInt {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}
impl Rem for ModInt {
    type Output = Self;
    fn rem(self, rhs: Self) -> Self::Output {
        let c = check_mod_eq(&self, &rhs);
        if !c.1 {
            panic!("modulo between two instance is different!")
        }
        Self {
            num: self.num % rhs.num,
            _modulo: Modulo::Static(c.0),
        }
    }
}
impl RemAssign for ModInt {
    fn rem_assign(&mut self, rhs: Self) {
        *self = *self % rhs
    }
}
impl Zero for ModInt {
    fn zero() -> Self {
        ModInt {
            num: 0,
            _modulo: Modulo::Dynamic,
        }
    }
    fn is_zero(&self) -> bool {
        self.num == 0
    }
}
impl One for ModInt {
    fn one() -> Self {
        ModInt {
            num: 1,
            _modulo: Modulo::Dynamic,
        }
    }
    fn is_one(&self) -> bool {
        self.num == 1
    }
}
impl Num for ModInt {
    type FromStrRadixErr = ParseIntError;
    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
        let num = str
            .chars()
            .rev()
            .enumerate()
            .map(|(i, b)| radix.pow(i as u32) as i64 * b.to_digit(radix).unwrap() as i64)
            .sum::<i64>();
        Ok(ModInt {
            num,
            _modulo: Modulo::Dynamic,
        })
    }
}
impl Pow<usize> for ModInt {
    type Output = Self;
    fn pow(mut self, mut exp: usize) -> Self::Output {
        if exp == 0 {
            return Self::one();
        }
        while exp & 1 == 0 {
            self = self * self;
            exp >>= 1;
        }
        if exp == 1 {
            return self;
        }
        let mut acc = self;
        while exp > 1 {
            exp >>= 1;
            self = self * self;
            if exp & 1 == 1 {
                acc = acc * self;
            }
        }
        acc
    }
}
macro_rules ! impl_ops_between_mint_and_primitive {($ ($ t : ty ) ,* ) => {$ (impl Add <$ t > for ModInt {type Output = Self ; fn add (self , rhs : $ t ) -> Self :: Output {self + Self :: new (rhs as i64 , self . get_mod () ) } } impl AddAssign <$ t > for ModInt {fn add_assign (& mut self , rhs : $ t ) {* self = * self + rhs ; } } impl Sub <$ t > for ModInt {type Output = Self ; fn sub (self , rhs : $ t ) -> Self :: Output {self - Self :: new (rhs as i64 , self . get_mod () ) } } impl SubAssign <$ t > for ModInt {fn sub_assign (& mut self , rhs : $ t ) {* self = * self - rhs ; } } impl Mul <$ t > for ModInt {type Output = Self ; fn mul (self , rhs : $ t ) -> Self :: Output {self * Self :: new (rhs as i64 , self . get_mod () ) } } impl MulAssign <$ t > for ModInt {fn mul_assign (& mut self , rhs : $ t ) {* self = * self * rhs ; } } impl Div <$ t > for ModInt {type Output = Self ; fn div (self , rhs : $ t ) -> Self :: Output {self / Self :: new (rhs as i64 , self . get_mod () ) } } impl DivAssign <$ t > for ModInt {fn div_assign (& mut self , rhs : $ t ) {* self = * self / rhs ; } } ) * } ; }
impl_ops_between_mint_and_primitive!(usize, u8, u16, u32, u64, isize, i8, i16, i32, i64);

#[macro_export]
macro_rules ! minimum {($ ($ e : expr ) ,+ ) => {{let mut res = None ; $ (match res {Some (v ) => res = Some (std :: cmp :: min (v , $ e ) ) , None => res = Some ($ e ) , } ) + res . unwrap () } } ; }
#[macro_export]
macro_rules ! maximum {($ ($ e : expr ) ,+ ) => {{let mut res = None ; $ (match res {Some (v ) => res = Some (std :: cmp :: max (v , $ e ) ) , None => res = Some ($ e ) , } ) + res . unwrap () } } ; }