module main; // https://kmjp.hatenablog.jp/entry/2015/12/18/0900 より // 誘導部分グラフ、動的計画法 import std; // 多次元配列をある値で埋める void fill(A, T)(ref A a, T value) if (isArray!A) { alias E = ElementType!A; static if (isArray!E) { foreach (ref e; a) fill(e, value); } else { a[] = value; } } void main() { // 入力 int N, M; readln.chomp.formattedRead("%d %d", N, M); auto W = readln.split.to!(int[]); // 答えの計算 // dp[最初の点の選択の有無][直前の点の選択の有無][頂点番号][選択済み頂点数] := そのような状態を満たす最大スコア auto dp = new int[][][][](2, 2, N + 1, M + 1); fill(dp, -100_000_000); dp[0][0][0][0] = dp[1][1][0][1] = 0; int ma = -100_000_000; foreach (r; 0 .. 2) { foreach (i; 0 .. N - 1) { foreach (j; 0 .. M + 1) { dp[r][0][i + 1][j] = max(dp[r][0][i][j], dp[r][1][i][j]); if (j) dp[r][1][i + 1][j] = max(dp[r][0][i][j - 1], dp[r][1][i][j - 1] + W[i]); } } ma = max(ma, dp[r][0][N - 1][M]); if (r == 0) ma = max(ma, dp[r][1][N - 1][M]); if (r == 1) ma = max(ma, dp[r][1][N - 1][M] + W[N - 1]); } // 答えの出力 writeln(ma); }