Problem:
Score : 400 points

Problem Statement

Your friend gave you a dequeue D as a birthday present.

D is a horizontal cylinder that contains a row of N jewels.

The values of the jewels are V_1, V_2, ..., V_N from left to right. There may be jewels with negative values.

In the beginning, you have no jewel in your hands.

You can perform at most K operations on D, chosen from the following, at most K times (possibly zero):

Operation A: Take out the leftmost jewel contained in D and have it in your hand. You cannot do this operation when D is empty.

Operation B: Take out the rightmost jewel contained in D and have it in your hand. You cannot do this operation when D is empty.

Operation C: Choose a jewel in your hands and insert it to the left end of D. You cannot do this operation when you have no jewel in your hand.

Operation D: Choose a jewel in your hands and insert it to the right end of D. You cannot do this operation when you have no jewel in your hand.

Find the maximum possible sum of the values of jewels in your hands after the operations.

Constraints

All values in input are integers.

1 \leq N \leq 50

1 \leq K \leq 100

-10^7 \leq V_i \leq 10^7

Input

Input is given from Standard Input in the following format:

N K
V_1 V_2 ... V_N

Output

Print the maximum possible sum of the values of jewels in your hands after the operations.

Sample Input 1

6 4
-10 8 2 1 2 6

Sample Output 1

14

After the following sequence of operations, you have two jewels of values 8 and 6 in your hands for a total of 14, which is the maximum result.

Do operation A. You take out the jewel of value -10 from the left end of D.

Do operation B. You take out the jewel of value 6 from the right end of D.

Do operation A. You take out the jewel of value 8 from the left end of D.

Do operation D. You insert the jewel of value -10 to the right end of D.

Sample Input 2

6 4
-6 -100 50 -2 -5 -3

Sample Output 2

44

Sample Input 3

6 3
-6 -100 50 -2 -5 -3

Sample Output 3

0

It is optimal to do no operation.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Text;
using System.Numerics;
using System.IO;


namespace SolutionCS
{
    class Program
    {
        public class TestElem : IComparable
        {
            public int value;
            public int num;

            public TestElem(int v, int n)
            {
                value = v;
                num = n;
            }

            public int CompareTo(object obj)
            {
                TestElem other = (TestElem)obj;

                return -value.CompareTo(other.value);
            }
        }

        public class PriorityQueue<T> where T : IComparable
        {
            T[] heap;
            int count = 0;

            public PriorityQueue(int maxSize)
            {
                heap = new T[maxSize];
                count = 0;
            }

            public void Push(T elem)
            {
                // 要素をPushするインデックス(枝の末尾部分)
                int i = count;

                // 要素数を増やす
                count++;

                // 親(i=0)に向かってたどる
                while (i > 0)
                {
                    // 親のインデックス
                    int p = (i - 1) / 2;

                    // elemのほうが大きいか同一の場合、Pushするインデックス確定
                    if (heap[p].CompareTo(elem) <= 0)
                    {
                        break;
                    }

                    // 親→子にコピーして再度親との比較を行う
                    heap[i] = heap[p];
                    i = p;
                }

                // 要素を決まったインデックスに入れる
                heap[i] = elem;
            }

            public T Pop()
            {
                // 要素なしの場合、Exception
                if (count == 0)
                {
                    throw new InvalidOperationException();
                }

                // 要素数減らす
                count--;

                // 返す要素を保存
                T result = heap[0];

                // 一番末端の要素(これを親から比較して配列に配置する)
                T x = heap[count];

                // 親から末尾に向かって子→親入れ替えを行う
                int i = 0;
                while (i * 2 + 1 < count)
                {
                    int l = i * 2 + 1;      // 子の左枝のインデックス
                    int r = i * 2 + 2;      // 子の右枝のインデックス

                    // 右が範囲外ではない、右のほうが小さいか検証
                    if (r < count && heap[r].CompareTo(heap[l]) < 0)
                    {
                        // 右のほうが小さい場合、上に上がっていくのは右のインデックス
                        l = r;
                    }

                    // x(配列の一番最後の要素)と比べて、大きければおわり
                    if (heap[l].CompareTo(x) >= 0)
                    {
                        break;
                    }

                    // 一個親側に繰り上げ
                    heap[i] = heap[l];

                    // 処理した枝のインデックスを与え、再度入れ替え
                    i = l;
                }

                // 一番末尾の要素を新たに保存
                heap[i] = x;

                // 最初に保存していた結果を返す
                return result;
            }

            public int Count { get { return count; } }
            public T Peek { get { return heap[0]; } }
        }

        static int N;
        static int K;
        static int[] v;
        static int[] g;

        static void Main(string[] args)
        {
            string[] s = Console.ReadLine().Split(' ');

            N = int.Parse(s[0]);
            K = int.Parse(s[1]);
            v = new int[N];
            g = new int[K];

            s = Console.ReadLine().Split(' ');
            for (int i = 0; i < N; i++)
            {
                v[i] = int.Parse(s[i]);
            }

            int ans = 0;
            for (int i = 1; i <= K; i++)
            {
                ans = Math.Max(ans, Solve(i));
            }

            Console.WriteLine(ans);
        }

        // k回の手順での最大値を求める
        static int Solve(int k)
        {
            int ans = 0;

            // 取得する数を１～kまで試行する(N個までしかできない）
            for (int i = 1; i <= Math.Min(k, N); i++)
            {
                // 取得する数：i
                // 戻す数：k-i
                // 残る数：i-(k-i) = 2i-k

                // 残る数がない場合、試行しない
                if ( i * 2 - k <= 0)
                {
                    continue;
                }

                // 左側から取るのを0～iまで試行する
                for (int left = 0; left <= i; left++)
                {
                    Get(left, i - left);

                    Array.Sort(g, 0, i);
                    Array.Reverse(g, 0, i);

                    int ans0 = 0;
                    for (int t = 0; t < i * 2 - k; t++)
                    {
                        ans0 += g[t];
                    }

                    ans = Math.Max(ans, ans0);
                }
            }

            return ans;
        }

        static void Get(int left, int right)
        {
            for (int i = 0; i < left; i++)
            {
                g[i] = v[i];
            }
            for (int i = 0; i < right; i++)
            {
                g[left + i] = v[N - i - 1];
            }
        }
    }
}