// clang-format off
	#include <bits/stdc++.h>
	using namespace std; using ll = long long; using uint = unsigned int;
	#define SFINAE(x, ...)	template <class, class = void> struct x : false_type {}; template <class T> struct x<T, void_t<__VA_ARGS__>> : true_type {};
	SFINAE(DefaultIO, decltype(cout << declval<T &>()))
	SFINAE(IsTuple, typename tuple_size<T>::type)
	SFINAE(Iterable, decltype(begin(declval<T>())))
	template <class T> constexpr char Space(const T &) { return (Iterable<T>::value or IsTuple<T>::value) ? '\n' : ' '; }
	template <auto &os> struct Writer {
		template <class T> void Impl(T const &t) const {
			if constexpr (DefaultIO<T>::value) os << t;
			else if constexpr (Iterable<T>::value) { int i = 0; for (auto &&x : t) ((i++) ? (os << Space(x), Impl(x)) : Impl(x)); }
			else if constexpr (IsTuple<T>::value) apply([this](auto const &... args) { int i = 0; (((i++) ? (os << ' ', Impl(args)) : Impl(args)), ...);}, t);
			else static_assert(IsTuple<T>::value, "No matching type for print");
		}
		template <class F, class... Ts> auto &operator()(F const &f, Ts const &... ts) const { return Impl(f), ((os << ' ', Impl(ts)), ...), os << '\n', *this; }
	};
	template <auto &is> struct Reader {
		template <class T> auto& operator()(T &t) const {
			if constexpr (DefaultIO<T>::value) is >> t;
			else if constexpr (Iterable<T>::value) for (auto &x : t) (*this)(x);
			else if constexpr (IsTuple<T>::value) apply([this](auto &... args) { ((*this)(args), ...); }, t);
			else static_assert(IsTuple<T>::value, "No matching type for read");
			return *this;
		}
	};
	#ifdef NARUT_LOCAL
	#define Debug(...) cerr << "\033[0;31m", Writer<cerr>{}(__VA_ARGS__), cerr << "\033[0m\n"
	#else
	#define Debug(...) 0
	#endif
	[[maybe_unused]] constexpr Reader<cin> Cin; [[maybe_unused]] constexpr Writer<cout> Cout;
	#define FOR(i, j, n) for (int i = int(j); i < int(n); ++i)
	#define ROF(i, j, n) for (int i = int(n) - 1; i >= int(j); --i)
// clang-format on


template <class T, class AddT, class MultT, T P> struct ModNum {
	using value_type = T;
	using add_type = AddT;
	using mult_type = MultT;
	static constexpr T mod_value = P;

	T val = 0;
	constexpr ModNum() = default;
	constexpr ModNum(T x) : val(x) {}
	template <class S> static constexpr ModNum Safe(S x) {
		return static_cast<T>(((x % P) + P) % P);
	}
	explicit constexpr operator value_type const &() const { return val; }

	constexpr bool operator==(ModNum rhs) const { return val == rhs.val; }
	constexpr bool operator!=(ModNum rhs) const { return val != rhs.val; }
	constexpr ModNum operator-() const { return (val == 0) ? (*this) : (P - val); }

	constexpr ModNum &operator+=(ModNum rhs) { return *this = Add(val, rhs.val); }
	constexpr ModNum &operator-=(ModNum rhs) { return *this = Sub(val, rhs.val); }
	constexpr ModNum &operator*=(ModNum rhs) { return *this = Mult(val, rhs.val); }
	constexpr ModNum &operator/=(ModNum rhs) { return *this *= rhs.Inverse(); }

	template <class S> constexpr ModNum Pow(S ex) const {
		if (P == 1) return 0;
		if (ex < 0) return Pow(-ex).Inverse();
		ModNum result = 1;
		ModNum base(*this);
		while (ex > 0) {
			if (ex & 1) result *= base;
			ex >>= 1;
			base *= base;
		}
		return result;
	}
	constexpr ModNum Inverse() const { return Pow(P - 2); }
	friend constexpr ModNum operator+(ModNum lhs, ModNum rhs) { return Add(lhs.val, rhs.val); }
	friend constexpr ModNum operator-(ModNum lhs, ModNum rhs) { return Sub(lhs.val, rhs.val); }
	friend constexpr ModNum operator*(ModNum lhs, ModNum rhs) { return Mult(lhs.val, rhs.val); }
	friend constexpr ModNum operator/(ModNum lhs, ModNum rhs) { return lhs * rhs.Inverse(); }

  private:
	static constexpr T Add(AddT lhs, AddT rhs) {
		auto sum = lhs + rhs;
		return (sum < P) ? sum : (sum - P);
	}
	static constexpr T Sub(AddT lhs, AddT rhs) {
		auto dif = lhs - rhs;
		return (dif >= 0) ? dif : (dif + P);
	}
	static constexpr T Mult(MultT lhs, MultT rhs) { return static_cast<T>((lhs * rhs) % P); }
	friend ostream &operator<<(ostream &os, ModNum m) { return os << m.val; }
	friend istream &operator>>(istream &is, ModNum &m) {
		is >> m.val;
		return is;
	}
};
using Num = ModNum<int, int, int64_t, 1000000007>;


auto Main() {
	int n,k;
	cin>>n>>k;

	vector<int> pos, neg;
	FOR(ni,0,n) {
		int a;
		cin>>a;
		if(a>0) pos.push_back(a);
		else neg.push_back(-a);
	}
	if (k==n) {
		auto res = accumulate(pos.begin(), pos.end(), Num{1}, multiplies<>{});
		res *= accumulate(neg.begin(), neg.end(), Num{1}, multiplies<>{});
		if (neg.size() & 1) res *= Num::Safe(-1);
		return res;
	}

	sort(begin(pos), end(pos));
	sort(begin(neg), end(neg));	

	auto orig = neg;
	const auto Bad = [&]() {
		auto res = accumulate(orig.begin(), orig.begin()+k,
			Num::Safe(-1), multiplies<>{});
		return res;
	};

	auto kk = k;
	Num ans = 1;

	const auto getopt = [&](auto &v) -> optional<ll> {
		if (v.size() < 2) return {};
		return v.back() * 1ll * *(v.rbegin()+1);
	};
	while(kk > 0) {
		if(kk>=2) {
			auto opt1 = getopt(pos);
			auto opt2 = getopt(neg);

			if(!opt1 and !opt2) return Bad();
			bool chosen = [&]() {
				if(!opt1) return false;
				if(!opt2) return true;
				return *opt1 > *opt2;
			}();
			if(chosen) {
				ans *= Num::Safe(*opt1);
				pos.pop_back(), pos.pop_back();
			} else {
				ans *= Num::Safe(*opt2);
				neg.pop_back(), neg.pop_back();
			}
			kk -= 2;
		} else {
			if (pos.empty()) return Bad();
			ans *= pos.back();
			pos.pop_back();
			kk--;
		}
	}
	return ans;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout << fixed << setprecision(10);
#ifdef NARUT_LOCAL
	assert(freopen("io/test.in", "r", stdin));
	cin.exceptions(cin.badbit | cin.failbit);
	cerr << fixed << setprecision(10);
#endif

	cout<<Main();
}


Measured memory_bytes: 4788