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++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define rep(i, s, N) for(ll i{s}; i < (N); i++)
#define rem(i, N, s) for(ll i{N}; i > (s); i--)
using namespace std;using ll = long long;using ld = long double;using P = pair<ll,ll>;const int MOD = (int)1e9+7;const string rt = "\n", sp = " ";
/* 最大公約数 */template<typename T> T gcd(T a, T b){return b != 0 ? gcd(b, a % b) : a;}/* 最小公倍数 */template<typename T> T lcm(T a, T b){return a*b/gcd(a,b);}/* UnionFind */template<typename T> struct UnionFind{vector<T> par;UnionFind(T n) : par(n, -1){}void init(T n){par.assign(n, -1);}T root(T x){if (par[x] < 0) return x;else return par[x] = root(par[x]);}bool issame(T x, T y){return root(x) == root(y);}bool merge(T x, T y){x = root(x); y = root(y);if(x == y) return false;if(par[x] > par[y]) swap(x, y);par[x] += par[y];par[y] = x;return true;}int size(int x) {return -par[root(x)];}};/* コンビネーション */ll comb(ll n, ll r) {if(n < r) return 0;if ( r * 2 > n ) r = n - r;ll dividend = 1;ll divisor  = 1;for (ll i = 1; i <= r; ++i ) {dividend *= (n-i+1);divisor  *= i;}return dividend / divisor;}/* MODコンビネーション */template<typename T> ll combpm(T N_, T C_) {const int NUM_=400001;static ll fact[NUM_+1],factr[NUM_+1],inv[NUM_+1];if (fact[0]==0) {inv[1]=fact[0]=factr[0]=1;for (int i=2;i<=NUM_;++i) inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD;for (int i=1;i<=NUM_;++i) fact[i]=fact[i-1]*i%MOD, factr[i]=factr[i-1]*inv[i]%MOD;}if(C_<0 || C_>N_) return 0;return factr[C_]*fact[N_]%MOD*factr[N_-C_]%MOD;}/* 多次元ベクター */template<class T>vector<T> mvec(size_t a){return vector<T>(a);}template<class T, class... Ts>auto mvec(size_t a, Ts... ts){return vector<decltype(mvec<T>(ts...))>(a, mvec<T>(ts...));}/* 多次元デック */template<class T>deque<T> mdeq(size_t a){return deque<T>(a);}template<class T, class... Ts>auto mdeq(size_t a, Ts... ts){return deque<decltype(mdeq<T>(ts...))>(a, mdeq<T>(ts...));}/* テスト関数 */void test(ll n){cout << "test" << n << endl;}/* 小数点以下 */void fixsp(ll n){cout << fixed << setprecision(n);}void defsp(ll n){cout << defaultfloat << setprecision(n);}/* 重み付きUnionFind */struct WUnionFind {vector<int> par;vector<int> rank;WUnionFind(int n = 1) {init(n);}void init(int n = 1) {par.resize(n); rank.resize(n);for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0;}int root(int x) {if (par[x] == x) {return x;}else {int r = root(par[x]);return par[x] = r;}}bool issame(int x, int y) {return root(x) == root(y);}bool merge(int x, int y) {x = root(x); y = root(y);if (x == y) return false;if (rank[x] < rank[y]) swap(x, y);if (rank[x] == rank[y]) ++rank[x];par[y] = x;return true;}};/* 約数列挙 */deque<ll> divisor(ll n) {deque<ll> ret;for(ll i = 1; i * i <= n; i++) {if(n % i == 0) {ret.push_back(i);if(i * i != n) ret.push_back(n / i);}}sort(begin(ret), end(ret));return (ret);}/* 最頻値 */template<typename T> auto mode(T data){if(data.size() == 1) return *begin(data);sort(begin(data), end(data));typename decltype(data)::value_type mode{};size_t n{},count{1};for(auto iter = adjacent_find(begin(data), end(data)),last = end(data), next = end(data); iter != last;){next = upper_bound(iter, last, *iter);count = distance(iter,next);if(n < count) n = count, mode = *iter;iter = adjacent_find(next, last);}return mode;}/* 中央値 */template<typename T> auto median(T data){sort(begin(data), end(data));size_t median_index = data.size() / 2;return (data.size() % 2 == 0? static_cast<double>(data[median_index] + data[median_index - 1]) / 2: data[median_index]);}/* IO高速化 */void fastio(){ios::sync_with_stdio(false);cin.tie(NULL);}

/* ここからコード開始 */

int main(){
  fastio;
  ll N;
  cin >> N;
  auto A = mdeq<ll>(N+1);
  rep(i, 0, N){
    cin >> A[i+1];
    A[i+1] = A[i] + A[i+1];
  }
  ll sp1{0}, sp2{0}, sp3{0};
  ll ans{MOD};
  auto P = [&](){return A[sp1] - A[0];};
  auto Q = [&](){return A[sp2] - A[sp1];};
  auto R = [&](){return A[sp3] - A[sp2];};
  auto S = [&](){return A[N] - A[sp3];};
  auto write = [&](){
    cout << sp1 << sp2 << sp3 << sp << P() << sp << Q() << sp << R() << sp << S() << sp;
    ans = min(ans, max({P(),Q(),R(),S()}) - min({P(),Q(),R(),S()}));
    cout << ans << rt;
  };
  auto rule = [&](){
    return 0 < sp1 && sp1 < sp2 && sp2 < sp3 && sp3 < N;
  };
  while(max({sp1, sp2, sp3}) < N){
    while(P() < Q()){
      sp1++;
    }
    while(R() < S()){
      sp3++;
    }
    sp1--;
    if(rule()) write();
    sp3--;
    if(rule()) write();
    sp1++;
    if(rule()) write();
    sp3++;
    if(rule()) write();
    sp2++;
  }
  cout << ans << rt;
}