*This is the advanced version of the 
[Minimum and Maximum Product of k Elements](https://www.codewars.com/kata/minimum-and-maximum-product-of-k-elements/) kata.*

---

Given a list of **integers** and a positive integer `k` (> 0), find the minimum and maximum possible product of `k` elements taken from the list.

If you cannot take enough elements from the list, return `None`/`nil`.

## Examples

```python
numbers = [1, -2, -3, 4, 6, 7]

k = 1  ==>  -3, 7
k = 2  ==>  -21, 42    # -3*7, 6*7
k = 3  ==>  -126, 168  # -3*6*7, 4*6*7
k = 7  ==>  None       # there are only 6 elements in the list
```

Note: the test lists can contain up to 500 elements, so a naive approach will not work.

---

## My other katas

If you enjoyed this kata then please try [my other katas](https://www.codewars.com/collections/katas-created-by-anter69)! :-)

#### *Translations are welcome!*

```python

USER_FILENAME = "<user_code>"
import sys, json, builtins
import math, heapq, bisect, itertools, functools, collections, statistics, fractions, decimal, operator, array, random, re, string, os, pathlib
try:
    import resource as _res
except Exception:
    _res = None
from collections import Counter, defaultdict, deque, OrderedDict
from functools import lru_cache, reduce
from itertools import accumulate, permutations, combinations, product
from math import gcd, ceil, floor, sqrt
from decimal import Decimal
try:
    from typing import *
except Exception:
    pass
try:
    sys.setrecursionlimit(1_000_000)
except Exception:
    pass
try:
    import site as _site
    try:
        _sys_sites = _site.getsitepackages() if hasattr(_site, "getsitepackages") else []
        for _p in _sys_sites:
            if _p and _p not in sys.path:
                sys.path.append(_p)
    except Exception:
        pass
    try:
        _usp = _site.getusersitepackages()
        if isinstance(_usp, str):
            _usp = [_usp]
        for _p in _usp:
            if _p and _p not in sys.path:
                sys.path.append(_p)
    except Exception:
        pass
except Exception:
    pass

def _disabled_input(*args, **kwargs):
    raise RuntimeError("input() is disabled in callable mode")
builtins.input = _disabled_input

ns = {"__name__": "__judge__"}  # prevent if __name__ == "__main__" blocks
for _k, _v in list(globals().items()):
    if not _k.startswith("_"):
        ns[_k] = _v
_CODE = "def find_min_max_product(arr, k):\n    \n    if k>len(arr):\n        return None\n    \n    if k==1:\n        return min(arr), max(arr)\n    \n    if k==len(arr):\n        res = eval('*'.join([str(i) for i in arr]))\n        return res, res\n    \n    arr = sorted(arr)\n    \n    arr_abs = sorted([abs(i) for i in arr])\n    max_abs = max(arr_abs)\n    pos = len([i for i in arr if i > 0])\n    pos_all = [i for i in arr if i > 0]\n    neg_all = [i for i in arr if i < 0]\n    neg = len([i for i in arr if i < 0])\n    zer = len([i for i in arr if i == 0])\n\n    if pos==0 and zer==0 and k%2==0:\n        min_both = arr[-k:]\n        max_both = arr[:k] \n        \n    if pos==0 and zer==0 and k%2!=0:\n        min_both = arr[:k]\n        max_both = arr[-k:]\n        \n    if pos==0 and zer!=0 and k%2==0:\n        min_both = [0]\n        max_both = arr[:k]\n        \n    if pos==0 and zer!=0 and k%2!=0:\n        min_both = arr[:k]\n        max_both = [0]\n        \n    if neg==0 and zer==0:\n        min_both = arr[:k]\n        max_both = arr[-k:] \n        \n    if neg==0 and zer!=0:\n        min_both = [0]\n        max_both = arr[-k:]  \n        \n    if pos!=0 and neg!=0:\n        for_sort = sorted([[i, abs(i)] for i in arr], key=lambda i:i[1])\n        for_sort = [i[0] for i in for_sort]\n\n        all_pos = [i for i in for_sort if i>0]\n        all_neg = [i for i in for_sort if i<0]\n        \n        max_pos = [i for i in for_sort[-k:] if i>0]\n        max_neg = [i for i in for_sort[-k:] if i<0]\n        \n        for i in range(len(all_pos)-len(max_pos)):\n            max_pos.insert(0,0)\n            \n        for i in range(len(all_neg)-len(max_neg)):\n            max_neg.insert(0,0)\n        \n        pos_reserve = [a-b for a,b in zip(all_pos,max_pos)]\n        neg_pos_reserve = [a-b for a,b in zip(all_neg,max_neg)]\n\n        pos_reserve = [i for i in pos_reserve if not i==0]\n        neg_pos_reserve = sorted([i for i in neg_pos_reserve if not i==0])\n        max_pos = [i for i in max_pos if not i==0]\n        max_neg = [i for i in max_neg if not i==0]\n        \n        max_pos_alt = [i for i in for_sort[-k:] if i>0]\n        max_neg_alt = [i for i in for_sort[-k:] if i<0]\n\n        if len(max_neg)>0 and len(max_neg)%2 and len(pos_reserve)>0:\n            max_neg.pop(0)\n            max_pos.append(pos_reserve[-1])\n            if len(max_pos_alt)>0 and len(neg_pos_reserve)>0:\n                max_pos_alt.pop(0)\n                max_neg_alt.append(neg_pos_reserve[0])\n        elif len(max_neg)>0 and len(max_neg)%2 and len(pos_reserve)==0:\n            max_pos.pop(0)\n            max_neg.append(neg_pos_reserve[0])\n        elif len(max_neg)==1 and len(neg_pos_reserve)>0:\n            max_pos.pop(0)\n            max_neg.append(neg_pos_reserve[0])\n        elif len(max_neg)==1 and len(pos_reserve)>0:\n            max_neg.pop(0)\n            max_pos.append(pos_reserve[0])\n\n        \n        min_pos = [i for i in for_sort[-k:] if i>0]\n        min_neg = [i for i in for_sort[-k:] if i<0]\n\n        for i in range(len(all_pos)-len(min_pos)):\n            min_pos.insert(0,0)\n            \n        for i in range(len(all_neg)-len(min_neg)):\n            min_neg.insert(0,0)\n        \n        neg_reserve = [a-b for a,b in zip(all_neg,min_neg)]\n        pos_reserve_neg = [a-b for a,b in zip(all_pos,min_pos)]\n        \n        neg_reserve = sorted([i for i in neg_reserve if not i==0])\n        pos_reserve_neg = [i for i in pos_reserve_neg if not i==0]\n        \n        pos_reserve_neg_alt = pos_reserve_neg\n        \n        min_pos = [i for i in min_pos if not i==0]\n        min_neg = [i for i in min_neg if not i==0]\n\n        min_pos_alt = [i for i in for_sort[-k:] if i>0]\n        min_neg_alt = [i for i in for_sort[-k:] if i<0]\n\n        if not len(min_neg)%2:\n            if len(min_neg_alt)>0 and len(pos_reserve_neg_alt)>0:\n                min_neg_alt.pop(0)\n                min_pos_alt.append(pos_reserve_neg_alt[-1])\n            try:\n                min_neg.append(neg_reserve[0])\n                min_pos.pop(0)\n            except:\n                try:\n                    min_neg.pop(0)\n                    min_pos.append(pos_reserve_neg[-1])\n                except:\n                    pass\n                \n        elif not len(min_neg)%2 and 0 in arr:\n            min_neg.append(0)\n\n        max_both = max_pos+max_neg\n        max_both_alt = max_pos_alt+max_neg_alt\n        \n        min_both = min_pos+min_neg\n        min_both_alt = min_pos_alt+min_neg_alt\n         \n    mn = eval('*'.join([str(i) for i in min_both]))\n    mx = eval('*'.join([str(i) for i in max_both]))\n    \n    try:\n        mx_alt = eval('*'.join([str(i) for i in max_both_alt]))\n    except:\n        mx_alt = -10**1000\n         \n    try:\n        mn_alt = eval('*'.join([str(i) for i in min_both_alt]))\n    except:\n        mn_alt = 10**1000\n        \n    \n    return min(mn,mn_alt), max(mx,mx_alt)"
_co = compile(_CODE, USER_FILENAME, "exec")
exec(_co, ns, ns)

_target = None
_fn_name = 'find_min_max_product'
if _fn_name:
    if "Solution" in ns:
        try:
            _obj = ns["Solution"]()
            if hasattr(_obj, _fn_name):
                _target = getattr(_obj, _fn_name)
        except Exception:
            _target = None
    if _target is None and _fn_name in ns and callable(ns[_fn_name]):
        _target = ns[_fn_name]
# Fallback: if there's exactly one user-defined function, use it
if _target is None:
    _cands = [v for k, v in ns.items() if callable(v) and getattr(v, "__module__", "") in ("__judge__", "__main__")]
    _user_funcs = [c for c in _cands if getattr(c, "__name__", "").startswith("_") is False]
    if len(_user_funcs) == 1:
        _target = _user_funcs[0]
if _target is None:
    raise RuntimeError(f"Could not resolve callable '{_fn_name}'")

_raw = sys.stdin.read().strip()
if _raw:
    _parsed = json.loads(_raw)
    if isinstance(_parsed, dict):
        _kwargs = _parsed.get("kwargs", {})
        _args = _parsed.get("args", [])
    else:
        _args, _kwargs = _parsed, {}
else:
    _args, _kwargs = [], {}
if not isinstance(_args, (list, tuple)):
    _args = [_args]
_res = _target(*_args, **_kwargs)
try:
    sys.stdout.write(repr(_res) + "\n")
except Exception:
    pass

```

Measured memory_bytes: 23652