#include #include using namespace std; #define rep(i, l, r) for (ll i = (l); i < (r); i++) #define drep(i, l, r) for (long long i = (r) - 1; i >= l; i--) #define nall(a) a.begin(), a.end() using ll = long long; using lll = __int128; using P = pair; template using vc = vector; template using vvc = vc>; template auto find_exactly(vector &a, T x) { auto t = lower_bound(nall(a), x); if (t == a.end() || *t != x) return a.end(); return t; } // template bool kaibun(string &v) { ll y = v.size(); rep(i, 0, (y + 1) / 2) { if (v[i] != v[y - 1 - i]) { return false; } } return true; } ll floor(ll x, ll m) { ll r = (x % m + m) % m; return (x - r) / m; // 負の数の割り算をしたいときに使う //-7/2=-4になるこれだったら } ll cross(ll ax, ll ay, ll bx, ll by) { // 二つのベクトルの外積を求める return ax * by - ay * bx; // これが0だったら平行 // 原点->a->bの順にまわる } ll dot(ll ax, ll ay, ll bx, ll by) { // ベクトルの内積を求める return ax * bx + ay * by; // これが0だったら垂直 } bool ispoint(ll px, ll py, ll qx, ll qy, ll rx, ll ry, ll sx, ll sy) { ll bigx = px - qx; ll bigy = py - qy; ll smallx = rx - sx; ll smally = ry - sy; ll vec = cross(bigx, bigy, smallx, smally); if (vec != 0) return true; else { ll tx = rx - px; ll ty = ry - py; if (cross(bigx, bigy, tx, ty) == 0) return true; return false; } // 2直線が交点を持つかを判定するヨ } bool isout_grid(ll i, ll j, ll h, ll w) { // グリッド内ならfalseグリッド外ならtrue return (!(0 <= i && i < h && 0 <= j && j < w)); } void Yes(bool a) { if (a) { cout << "Yes" << endl; return; } else { cout << "No" << endl; return; } } bool compare(P &a, P &b) { return a.first - a.second > b.first - b.second; // <で小さい順 >で大きい順 // pairのsecondでソートする比較関数 // >で大きい順 <で小さい順 // sort(配列名.begin(),配列名.end(),compare)で使える } ll kyoutuuhanni(P a, P b) { ll q = max(a.first, b.first); ll e = min(a.second, b.second); if (e - q < 0) { return 0; } else { return e - q + 1; } } ll binary(ll n) { // n以下の数を探すみたいなやつ改造して ll l = 0; ll r = 1e9; ll mid; while (r - l > 1) { mid = (l + r) / 2; if (mid <= n) { l = mid; } else if (mid > n) { r = mid; } } return l; } ll infinity = 8e18; // long long の上限(約 9.22×10^18) const int dx[] = {-1, 0, 1, 0, 1, 1, -1, -1}; const int dy[] = {0, 1, 0, -1, 1, -1, 1, -1}; // mapは必ずfirstとsecond long double kyori(ll x1, ll y1, ll x2, ll y2) { ll t = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); long double a = sqrt(t); return a; } bool isprime(ll n) { // 高速な素数判定 for (ll i = 2; i * i <= n; i++) { if (n % i == 0) { return false; } } return true; } long long modpow(long long a, long long n, long long mod) { // 高速な累乗の余り long long res = 1; while (n > 0) { if (n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res; } const ll mod = 998244353; vector fac(300001); // n!(mod M) vector ifac(300001); ll mpow(ll x, ll n) // 高速なべき乗計算 二分累乗法 { ll ans = 1; while (n != 0) { if (n & 1) ans = ans * x % mod; x = x * x % mod; n = n >> 1; } return ans; } ll comb(ll a, ll b) // 高速な組み合わせ計算 preparecombで初期化してから使う //もしa,bが負の値だとバグる { if (a == 0 && b == 0) return 1; if (a < b || a < 0) return 0; ll tmp = ifac[a - b] * ifac[b] % mod; return tmp * fac[a] % mod; } void preparecomb() // 3e5まで対応 階乗をあらかじめ計算しておく { fac[0] = 1; ifac[0] = 1; for (ll i = 0; i < 300000; i++) { fac[i + 1] = fac[i] * (i + 1) % mod; ifac[i + 1] = ifac[i] * mpow(i + 1, mod - 2) % mod; } } struct edge { ll cost; ll u; ll v; edge(ll a, ll b, ll c) : cost(a), u(b), v(c) {} }; struct edgecompare { bool operator()(const edge &a, const edge &b) const { return a.cost > b.cost; // min-heapにするので不等号は>向き } }; void cincout() { ios::sync_with_stdio(false); std::cin.tie(nullptr); cout << fixed << setprecision(15); } using namespace atcoder; using mint = modint998244353; // 問題を言い換えてみる? // 何が分かればいい? // どう更新するか int ran(ll i) { mt19937_64 mt64(i); return mt64(); } using mint = modint998244353; int main() { ll n, k; cin >> n >> k; if (((n - 1) / 2) + 1 < k) { cout << "Impossible" << endl; return 0; } vector sub(n); rep(i, 0, n) cin >> sub[i]; vector> dp(k + 1, vector(n + 1, -infinity)); rep(i, 0, n) { if (((n - i - 1) / 2) + 1 < k - 0) continue; dp[1][i + 1] = sub[i]; } // 遷移は // いまk個目を選んでいる // j番目までを考えている rep(i, 1, k) { rep(j, 0, n) { if (((n - j - 1) / 2) + 1 < k - i) { dp[i + 1][j + 1] = -infinity; continue; } if (j > 0) { dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j - 1] + sub[j]); } // sub[j]をk個目に選ぶ からk-2までの最大値を取る //+sub[j]が選ぶっていう動作 else { dp[i + 1][j + 1] = max(dp[i + 1][j], 0ll + sub[j]); } } } ll ans = -infinity; rep(i, 0, n) { ans = max(ans, dp[k][i + 1]); } cout << ans << endl; }