Problem:
Score : 600 points

Problem Statement

Snuke has an integer sequence A of length N.

He will make three cuts in A and divide it into four (non-empty) contiguous subsequences B, C, D and E.
The positions of the cuts can be freely chosen.

Let P,Q,R,S be the sums of the elements in B,C,D,E, respectively.
Snuke is happier when the absolute difference of the maximum and the minimum among P,Q,R,S is smaller.
Find the minimum possible absolute difference of the maximum and the minimum among P,Q,R,S.

Constraints

4 \leq N \leq 2 \times 10^5

1 \leq A_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
A_1 A_2 ... A_N

Output

Find the minimum possible absolute difference of the maximum and the minimum among P,Q,R,S.

Sample Input 1

5
3 2 4 1 2

Sample Output 1

2

If we divide A as B,C,D,E=(3),(2),(4),(1,2), then P=3,Q=2,R=4,S=1+2=3.
Here, the maximum and the minimum among P,Q,R,S are 4 and 2, with the absolute difference of 2.
We cannot make the absolute difference of the maximum and the minimum less than 2, so the answer is 2.

Sample Input 2

10
10 71 84 33 6 47 23 25 52 64

Sample Output 2

36

Sample Input 3

7
1 2 3 1000000000 4 5 6

Sample Output 3

999999994

Solution in C# (Mono-mcs 6.8.0.105) (judge verdict: Wrong Answer)

using System;
using System.Collections.Generic;
using System.Windows;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Atcoder
{
    public class Program
    {
        private static long mod = 1000000007;
        private static long max = 999999999999;

        static void Main(string[] args)
        {
            var n = Read().Int();
            var r = ReadSplit();
            var al = new Dictionary<long, int>();
            for (int i = 0; i < n; i++)
            {
                var val = r[i].Long() - (i + 1);
                if (al.ContainsKey(val))
                {
                    al[val]++;
                }
                else
                {
                    al.Add(val, 1);
                }
            }

            long tmp = 0;
            foreach (var item in al)
            {
                tmp += item.Key * item.Value;
            }
            long b = tmp / n;
            long ans = max;
            for (long i = -10; i <= 10; i++)
            {
                tmp = 0;
                foreach (var item in al)
                {
                    tmp += Math.Abs(Math.Abs(item.Key - (b + i)) * item.Value);
                }
                ans = Math.Min(ans, tmp);
            }
            WriteRead(ans);
        }

        public static List<long> GetCalcDivisor(long n)
        {
            var res = new List<long>();
            for (long i = 1L; i * i <= n; ++i)
            {
                if (n % i == 0)
                {
                    res.Add(i);
                    long j = n / i;
                    if (j != i) res.Add(j);
                }
            }
            res.Sort();
            return res;
        }

        class ModCombination
        {
            public long _mod = 1000000007;
            public int _max = 1000000;

            long[] fac;
            long[] finv;
            long[] inv;

            public ModCombination() : this(1000000007, 1000000)
            {
            }

            public ModCombination(long mod, int max)
            {
                _mod = mod;
                _max = max;
                fac = new long[max];
                finv = new long[max];
                inv = new long[max];
                fac[0] = fac[1] = 1;
                finv[0] = finv[1] = 1;
                inv[1] = 1;
                for (int i = 2; i < max; i++)
                {
                    fac[i] = fac[i - 1] * i % mod;
                    inv[i] = mod - inv[mod % i] * (mod / i) % mod;
                    finv[i] = finv[i - 1] * inv[i] % mod;
                }
            }

            public long Combination(int n, int m)
            {
                if (n < m) return 0;
                if (n < 0 || m < 0) return 0;
                return fac[n] * (finv[m] * finv[n - m] % _mod) % _mod;
            }
        }

        public static string Read()
        {
            return Console.ReadLine();
        }

        public static string[] ReadSplit()
        {
            return Console.ReadLine().Split(' ');
        }

        public static void WriteRead(object str)
        {
            Console.WriteLine(str);
            Read();
        }

        public static void Write(object str)
        {
            Console.WriteLine(str);
        }

        private static bool ChangeMin<T>(ref T a, T b) where T : IComparable
        {
            if (a.CompareTo(b) > 0)
            {
                a = b;
                return true;
            }
            return false;
        }

        private static bool ChangekMax<T>(ref T a, T b) where T : IComparable
        {
            if (b.CompareTo(a) > 0)
            {
                a = b;
                return true;
            }
            return false;
        }

        /*優先度付きキュー*/
        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 = true)
            {
                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;

                    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);
                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;
            }
        }

        private static bool NextPermutation(int[] array)
        {
            var size = array.Length;
            var ok = false;

            //array[i]<array[i+1]を満たす最大のiを求める
            int i = size - 2;
            for (; 0 <= i; i--)
            {
                if (array[i] < array[i + 1])
                {
                    ok = true;
                    break;
                }
            }

            //全ての要素が降順の場合、NextPermutationは存在しない
            if (ok == false) return false;

            //array[i]<array[j]を満たす最大のjを求める
            int j = size - 1;
            for (; ; j--)
            {
                if (array[i] < array[j]) break;
            }

            //iとjの要素をswapする
            var tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;

            //i以降の要素を反転させる
            Array.Reverse(array, i + 1, size - (i + 1));

            return true;
        }

        //要素数Nを引数として渡し、0～N-1でできた順列をすべて返す
        static List<int[]> GetAllPermutation(int N)
        {
            var res = new List<int[]>();
            var array = Enumerable.Range(0, N).ToArray();
            do
            {
                var copy = new int[N];
                array.CopyTo(copy, 0);
                res.Add(copy);
            } while (NextPermutation(array));

            return res;
        }

        //配列arrayを引数として渡し,辞書順がarray以上の順列をすべて返す
        static List<int[]> GetAllPermutation(int[] array)
        {
            var size = array.Length;
            var res = new List<int[]>();
            do
            {
                var copy = new int[size];
                array.CopyTo(copy, 0);
                res.Add(copy);
            } while (NextPermutation(array));

            return res;
        }

        public static long ModPow(long x, long n)
        {
            x = x % mod;
            if (n == 0)
            {
                return 1;
            }
            else if (n % 2 == 1)
            {
                return (x * ModPow(x, n - 1)) % mod;
            }
            else
            {
                return ModPow((x * x) % mod, n / 2) % mod;
            }
        }

        /// <summary>
        /// 最小公倍数
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static long Lcm(long a, long b)
        {
            return a / Gcd(a, b) * b;
        }
        /// <summary>
        /// 最大公約数
        /// </summary>
        /// <param name="m"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static long Gcd(long m, long n)
        {
            if (n == 0) return m;
            return Gcd(n, m % n);
        }
    }
}


public static class Extentions
{
    public static int Int(this object obj)
    {
        return int.Parse(obj.ToString());
    }

    public static long Long(this object obj)
    {
        return long.Parse(obj.ToString());
    }

    public static decimal Decimal(this object obj)
    {
        return decimal.Parse(obj.ToString());
    }

    public static double Double(this object obj)
    {
        return double.Parse(obj.ToString());
    }

    public static T2 GetValueZero<T1, T2>(this Dictionary<T1, T2> d, T1 key) where T2 : struct
    {
        T2 value;
        if (d.TryGetValue(key, out value))
        {
            return value;
        }
        return new T2();
    }
}