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 Kotlin (1.3.71) (judge verdict: Accepted)

import java.io.*
import java.util.*
import java.lang.Math.*


class LongMod(var num: Long, val MOD: Long = 1_000_000_007L) {
    init {
        this.num = (this.num%this.MOD + this.MOD)%this.MOD
    }
    constructor(numStr: String, MOD: Long = 1e9.toLong()+7) :
            this(0L, MOD) {
        if (numStr.isEmpty()) return
        var rv = numStr.reversed()
        var d = 1L
        rv.forEach{ c ->
            this.num += (c - '0') * d
            this.num %= MOD
            d *= 10
            d %= MOD
        }
    }
    override operator fun equals(other: Any?): Boolean {
        if (other !is LongMod) return false
        return this.num % this.MOD == other.num % this.MOD
    }
    operator fun unaryMinus(): LongMod {
        return LongMod(-this.num)
    }
    operator fun plusAssign(other: LongMod): Unit {
        if ((this.num + other.num) >= this.MOD) {
            this.num -= this.MOD
        }
        this.num += other.num
    }
    operator fun minusAssign(other: LongMod): Unit {
        if ((this.num + this.MOD - other.num) >= this.MOD) {
            this.num -= this.MOD
        }
        this.num += this.MOD - other.num
    }
    operator fun timesAssign(other: LongMod): Unit {
        this.num *= other.num
        this.num %= this.MOD
    }
    operator fun plus(other: LongMod): LongMod {
        val res = LongMod(this.num, this.MOD)
        res += other
        return res
    }
    operator fun minus(other: LongMod): LongMod {
        val res = LongMod(this.num, this.MOD)
        res -= other
        return res
    }
    operator fun times(other: LongMod): LongMod {
        val res = LongMod(this.num, this.MOD)
        res *= other
        return res
    }
    fun pow(n: Long): LongMod {
        if (n == 0L) return LongMod(1L, this.MOD)
        var x = this.pow(n / 2)
        x.timesAssign(x)
        if (n % 2 == 1L) x.timesAssign(this)
        return x
    }
    fun inv(): LongMod {
        return this.pow(this.MOD - 2)
    }
    operator fun divAssign(other: LongMod): Unit {
        this *= other.inv()
    }
    operator fun div(other: LongMod): LongMod {
        val res = LongMod(this.num, this.MOD)
        res /= other
        return res
    }
}

fun solve(K: Int, skP: Stack<Long>, skM: Stack<Long>, compare: (Long,Long)->Boolean): Pair<Long, Boolean> {
    var ans = LongMod(1L)
    var i = 0
    var minus = false
    while (i < K) {
        if (skM.size <= 1 || i == K-1) {
            if (skP.isNotEmpty()) {
                val p1 = skP.pop()!!
                ans = ans * LongMod(p1)
            } else {
                val m1 = skM.pop()!!
                ans = ans * LongMod(m1)
                minus = true
            }
            i++
            continue
        }

        assert(skM.size>=2)

        if (skP.isEmpty()) {
            val m1 = skM.pop()!!
            val m2 = skM.pop()!!
            ans = ans * LongMod(m1 * m2)
            i+=2
            continue
        }
        if (skP.size == 1) {
            val p1 = skP.pop()!!
            val m1 = skM.pop()!!
            val m2 = skM.pop()!!
            if (compare(p1, m1 * m2)) {
                ans = ans * LongMod(p1)
                skM.push(m2)
                skM.push(m1)
                i++
            } else {
                ans = ans * LongMod(m1 * m2)
                skP.push(p1)
                i+=2
            }
            continue
        }

        assert(skP.size>=2)
        val p1 = skP.pop()!!
        val p2 = skP.pop()!!
        val m1 = skM.pop()!!
        val m2 = skM.pop()!!
        if (compare(p1 * p2, m1 * m2)) {
            ans = ans * LongMod(p1)
            skP.push(p2)
            skM.push(m2)
            skM.push(m1)
            i++
        } else {
            ans = ans * LongMod(m1 * m2)
            skP.push(p2)
            skP.push(p1)
            i+=2
        }
    }

    return Pair(ans.num, minus)
}


fun main() {
    val (N, K) = rd.readIntArray()
    val A = rd.readLongArray()

    val PM = A.groupBy{ when {
        it >= 0 -> "nneg"
        else -> "minus"
    } }

    val ge: (Long, Long) -> Boolean = { a,b -> a >= b }
    val le: (Long, Long) -> Boolean = { a,b -> a <= b }

    val P = PM["nneg"]?.sorted() ?: emptyList()
    val M = PM["minus"]?.sorted() ?: emptyList()
    assert(P.size + M.size == N)

    val skP = Stack<Long>()
    val skM = Stack<Long>()
    if (K - min((M.size/2)*2, K/2*2) > P.size) {
        skP.addAll(P.reversed())
        skM.addAll(M)
        val pr = solve(K, skP, skM, le)
        assert(pr.second)
        println(pr.first)
    } else {
        skP.addAll(P)
        skM.addAll(M.reversed())
        val pr = solve(K, skP, skM, ge)
        println(pr.first)
    }
}


//val rd = debug.Reader("abc", "173", "e", "sample-2")
val rd = Reader()
fun main(args: Array<String>) {
    Thread(null, MainThread(), "mainThread", 128 * 1024 * 1024).start()
}


const val MOD = 1_000_000_007L; const val INF = Int.MAX_VALUE/2; const val LINF = Long.MAX_VALUE/2
const val EPS = 1e-9; fun DBLEQ(a: Double, b: Double): Boolean {return abs(a - b) < EPS}
data class IntPair(val first: Int, val second: Int)
data class To(val idx: Int, val cost: Long)
fun <T>edge(V: Int): Array<ArrayList<T>> { return Array(V){ArrayList<T>()} }
val errPrintln: (Any) -> Unit = { msg -> System.err.println(msg) }
class MainThread : Runnable {
    override fun run() { main() }
}
class Reader {
    private val br = BufferedReader(InputStreamReader(System.`in`))
    val readString: () -> String = { br.readLine() }
    val readInt: () -> Int = { br.readLine().toInt() }
    val readLong: () -> Long = { br.readLine().toLong() }
    val readIntArray: () -> IntArray = { br.readLine().split(' ').map { it.toInt() }.toIntArray() }
    val readLongArray: () -> LongArray = { br.readLine().split(' ').map { it.toLong() }.toLongArray() }
    val readListInt: () -> List<Int> = { br.readLine().split(' ').map { it.toInt() } }
    val readListLong: () -> List<Long> = { br.readLine().split(' ').map { it.toLong() } }
}