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.Numerics;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace debug
{
    class main
    {
        static void Main(string[] args)
        {
            //問題クラスを展開
            ProgramD a = new ProgramD();
            a.main();//実行する

        }

    }

    class ProgramA
    {
        public void main()
        {
            //まずは数を代入する
            string[] input = Console.ReadLine().Split(' ');
            int a = int.Parse(input[0]);
            int p = int.Parse(input[1]);

            //リンゴのかけらの数を求める
            int sum = a * 3 + p;

            //できるパイの数を計算
            sum = sum / 2;

            //出力
            Console.WriteLine(sum);
        }
            
    }

    class ProgramB
    {
        public void main()
        {
            int n = int.Parse(Console.ReadLine());
            List<Task> task = new List<Task>();

            //タスクで作っちゃう（3つ連動関数）
            for (int i = 0; i < n; i++)
            {
                string[] s = Console.ReadLine().Split(' ');

                task.Add(new Task(s[0], int.Parse(s[1]), i + 1));
            }

            //まず町の名前を小さい順、そして得点の高い順に並べる
            var sorted = task.OrderBy(t => t.town).ThenByDescending(t => t.point);

            foreach (var s in sorted)
            {
                Console.WriteLine(s.num);

            }

        }
    }

    public class Task
    {
        public string town;
        public int point;
        public int num;
        public Task(string town, int point, int num)
        {
            this.town = town;
            this.point = point;
            this.num = num;
        }
    }

    class ProgramC
    {
        public void main()
        {
            string[] t = Console.ReadLine().Split(' ');
            int n = int.Parse(t[0]);
            int m = int.Parse(t[1]);

            //スイッチがそれぞれオンオフを考える
            int[,] sw = new int[m, n];
            int[] power = new int[m];
            int[] count = new int[m];
            int ans = 0;

            //スイッチを押すと反応する電球を記憶
            for (int i = 0; i < m; i++)
            {
                string[] s = Console.ReadLine().Split(' ');
                for (int j = 0; j < int.Parse(s[0]); j++)
                    sw[i, int.Parse(s[j + 1]) - 1] = 1;

            }

            //最後のオンオフの条件も記録
            string[] u = Console.ReadLine().Split(' ');
            for (int i = 0; i < m; i++)
                power[i] = int.Parse(u[i]);


            //ビット全探索
            for (int i = 0; i < (1 << n); i++)
            {
                //まずはオンオフでオンしている数を数える
                for (int j = 0; j < n; j++)
                {
                    if (((i >> j) & 1) == 1)
                    {
                        for (int k = 0; k < m; k++)
                        {
                            if (sw[k, j] == 1)
                                count[k]++;
                        }

                    }
                }

                //もし一つでもオン状態がなければアウト
                for (int j = 0; j < m; j++)
                {
                    if (count[j] % 2 != power[j])
                        break;

                    if (j == m - 1)
                        ans++;

                }

                for (int j = 0; j < m; j++)
                    count[j] = 0;
            }

            Console.WriteLine(ans);
            return;
        }
    }



    
    class ProgramD
    {
        public void main()
        {
            //入力
            string[] s = Console.ReadLine().Split(' ');
            int n = int.Parse(s[0]);
            int k = int.Parse(s[1]);

            string[] v = Console.ReadLine().Split(' ');

            int ans = 0;

            //左から捨てるをA,右から捨てるをB回とする。A+B回<min(n.k)なので、そこからA,Bを全探索
            int num = Math.Min(n, k);
            for (int i = 0; i <= num; i++)
                for (int j = 0; j <= num; j++)
                {
                    //もしi+jでnumをこえるならとばす
                    if (i + j > num)
                        continue;

                    PriorityQueue<int> q = new PriorityQueue<int>(num, false);
                    //A個取り出す
                    for(int x = 0; x < i;x++)
                        q.Enqueue(int.Parse(v[x]));

                    //B個取り出す
                    for (int x = 0; x < j; x++)
                        q.Enqueue(int.Parse(v[n -1 - x]));
                    //K-A-B個捨てられるかどうか見る
                    for(int x = 0;x < Math.Min(k - (i+ j), i + j);x++)
                    {
                        if (q.Count == 0)
                            break;

                        int t = q.Dequeue();
                        if (t >= 0)//正だったらもう捨てられるのはないので入れておしまい
                        {
                            q.Enqueue(t);
                            break;
                        }
                    }
                    //全数を数える
                    int sum = 0;
                    int res = q.Count;
                    for (int x = 0; x < res; x++)
                        sum += q.Dequeue();

                    //最大更新
                    ans = Math.Max(ans, sum);

                }

            Console.WriteLine(ans);

        }
    }

    /*優先度付きキュー*/
    class PriorityQueue<T> where T : IComparable<T>
    {
        public readonly T[] Array;
        public readonly bool Greater;
        public int Count { get; private set; } = 0;


        public PriorityQueue(int capacity, bool greater)
        {
            this.Array = new T[capacity];
            this.Greater = greater;
        }

        //キューを追加
        public void Enqueue(T item)
        {
            this.Array[this.Count] = item;
            this.Count += 1;//数を足す
            this.UpHeap();　//最後尾に追加したところを移動させる
        }

        public T Dequeue()
        {
            // 先頭要素を末尾にして再構成
            this.Swap(0, this.Count - 1);
            this.Count -= 1;
            this.DownHeap();

            return this.Array[this.Count];
        }

        //親と比較して入れ替えていく
        private void UpHeap()
        {
            var n = this.Count - 1;
            while (n != 0)
            {
                // 親要素の座標
                var parent = (n - 1) / 2;

                //もし親の方がちいさいなら、交換する。
                if (this.Compare(this.Array[n], this.Array[parent]) > 0)
                {
                    this.Swap(n, parent);
                    n = parent;
                }
                else
                {
                    break;
                }
            }
        }

        //子と比較して入れ替えていく
        private void DownHeap()
        {
            var parent = 0;
            while (true)//無限ループ
            {
                var child = 2 * parent + 1;
                //子供がいないなら終わり
                if (child > this.Count - 1) break;

                //子供は2つあるので大きい方を対象にする
                if (child < this.Count - 1 && this.Compare(this.Array[child], this.Array[child + 1]) < 0)
                {
                    // 左より右の子のほうが大きい値の場合、右を入れ替え対象にする
                    child += 1;
                }

                //親と子を比較して子が大きいなら入れ替える。そうでないなら成立なのでおしまい。
                if (this.Compare(this.Array[parent], this.Array[child]) < 0)
                {
                    this.Swap(parent, child);
                    parent = child;
                }
                else
                {
                    break;
                }
            }
        }

        //aとbを比較する
        private int Compare(T a, T b)
        {
            var c = a.CompareTo(b);//a-b、正のときはaが大きく、負のときはbが大きい（任意もので処理できる）
            if (!this.Greater)
            {
                c = -c;
            }
            return c;
        }

        //aとbを入れ替える
        private void Swap(int a, int b)
        {
            var tmp = this.Array[a];
            this.Array[a] = this.Array[b];
            this.Array[b] = tmp;
        }
    }

    class ProgramE
    {
        static void main()
        {

            //入力
            string[] t = Console.ReadLine().Split(' ');
            int n = int.Parse(t[0]);
            int k = int.Parse(t[1]);

            int[] ans = new int[n];
            int count = 0;


            UnionFind tree = new UnionFind();//UnionFindクラスを設定
            tree.par = new int[n];
            tree.temp = new int[n];
            tree.reset(n);

            //木でくっつける
            for (int i = 0; i < k; i++)
            {
                string[] s = Console.ReadLine().Split(' ');
                int u = int.Parse(s[0]);
                int v = int.Parse(s[1]);
                int w = int.Parse(s[2]);
                tree.unite(u - 1, v - 1);
            }

            //それぞれの要素数ごとに数を分類
            for (int i = 0; i < n; i++)
                ans[tree.size(i) - 1]++;

            //要素数がiのものがある分を(i+1)で割れば、分類した木の数が出る
            for (int i = 0; i < n; i++)
                count += ans[i] / (i + 1);


            Console.WriteLine(count);
            return;

        }
    }

    /*UnionFind法のクラス*/
    class UnionFind
    {

        public int[] par;
        public int[] temp;


        //マイナスは根を示す。
        public void reset(int n)
        {
            for (int i = 0; i < n; i++)
                par[i] = -1;
        }

        //マイナスならそれはまだ属していないので根である。そうでないならさかのぼる
        public int root(int x)
        {
            if (par[x] < 0)
                return x;
            else
                return root(par[x]);
        }

        //根の併合を行い、根には要素数を足す（マイナスの値）
        public void unite(int x, int y)
        { // xとyの木を併合
            int rx = root(x); //xの根をrx
            int ry = root(y); //yの根をry
            if (rx == ry)
                return; //xとyの根が同じ(=同じ木にある)時はそのまま
            if (par[ry] > par[rx])
            {
                int temp = ry;
                ry = rx;
                rx = temp;
            }
            par[ry] += par[rx];
            par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
        }

        // 2つのデータx, yが属する木が同じならtrueを返す
        public bool same(int x, int y)
        {
            int rx = root(x);
            int ry = root(y);
            return rx == ry;
        }

        //根の元に入っている
        public int size(int x)
        {
            return -par[root(x)];
        }
    }


 

}