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 4.6.2.0) (judge verdict: Accepted)

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

public class Program
{

    public void Proc()
    {
        int inputCount = int.Parse(Reader.ReadLine());
        this.Items = Reader.ReadLine().Split(' ').Select(a => long.Parse(a)).ToArray();
        this.RuisekiWa = new long[inputCount];

        for (int i = 0; i < Items.Length; i++) {
            if(i==0) {
                this.RuisekiWa[0] = this.Items[0];
            }     else {
                this.RuisekiWa[i] = this.RuisekiWa[i - 1] + this.Items[i];
            }
        }

        long ans = long.MaxValue;

        for (int i = 1; i < Items.Length - 2; i++) {
            ans = Math.Min(ans, GetAns(i));            
        }
        Console.WriteLine(ans);

    }


    private long GetAns(int idx) {
        int firstSectionLast = GetIdx(0, idx, 0, idx - 1);
        long num1 = GetValue(0, firstSectionLast);
        long num2 = GetValue(firstSectionLast + 1, idx);

        int thirdSectionLast = GetIdx(idx + 1, Items.Length - 1, idx + 1, Items.Length - 2);

        long num3 = GetValue(idx + 1, thirdSectionLast);
        long num4 = GetValue(thirdSectionLast + 1, Items.Length - 1);

        long min = Math.Min(num1, Math.Min(num2, Math.Min(num3, num4)));
        long max = Math.Max(num1, Math.Max(num2, Math.Max(num3, num4)));

        return Math.Abs(max - min);
    }

    private int GetIdx(int startIdx, int endIdx, int min, int max) {
        if(max - min <= 2) {
            int mid = (max + min) / 2;
            long num1 = Math.Abs(GetValue(startIdx, min) - GetValue(min + 1, endIdx));
            long num2 = Math.Abs(GetValue(startIdx, mid) - GetValue(mid + 1, endIdx));
            long num3 = Math.Abs(GetValue(startIdx, max) - GetValue(max + 1, endIdx));
            if(num1<=num2&&num1 <= num3) {
                return min;
            } else if(num2 <= num1 && num2 <= num3){
                return mid;
            } else {
                return max;
            }
        }
        int mid1 = min + (max - min) / 3;
        int mid2 = max - (max - min) / 3;

        long val1 = Math.Abs(GetValue(startIdx, min) - GetValue(min + 1, endIdx));
        long val2 = Math.Abs(GetValue(startIdx, mid1) - GetValue(mid1 + 1, endIdx));
        long val3 = Math.Abs(GetValue(startIdx, mid2) - GetValue(mid2 + 1, endIdx));
        long val4 = Math.Abs(GetValue(startIdx, max) - GetValue(max + 1, endIdx));

        long minVal = new long[] { val1, val2, val3, val4 }.Min();
        if(val1 == minVal) {
            return GetIdx(startIdx, endIdx, min, mid1);
        } else if(val2 == minVal) {
            return GetIdx(startIdx, endIdx, min, mid2);
        } else if(val3 == minVal) {
            return GetIdx(startIdx, endIdx, mid1, max);
        } else {
            return GetIdx(startIdx, endIdx, mid2, max);
        }
    }

    private long GetValue(int startIdx, int endIdx) {
        long val = RuisekiWa[endIdx];
        if(startIdx > 0) {
            val -= RuisekiWa[startIdx - 1];
        }
        return val;
    }

    private long[] RuisekiWa;

    private long[] Items;





    public class Reader
    {
        static StringReader sr;
        public static bool IsDebug = false;
        public static string ReadLine()
        {
            if (IsDebug)
            {
                if (sr == null)
                {
                    sr = new StringReader(InputText.Trim());
                }
                return sr.ReadLine();
            }
            else
            {
                return Console.ReadLine();
            }
        }
        private static string InputText = @"



10
10 71 84 33 6 47 23 25 52 64



";
    }

    public static void Main(string[] args)
    {
#if DEBUG
        Reader.IsDebug = true;
#endif
        Program prg = new Program();
        prg.Proc();
    }
}