macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{next, $($r)*}
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

fn spmin(v : &[i64]) -> usize {
  let mut l = 1;
  let mut r = v.len();
  let sum = v[v.len() - 1] - v[0];
  while r - l > 1 {
    let m = (l + r) / 2;
    let a = v[m] - v[0];
    if a >= sum / 2 {
      r = m;
    } else {
      l = m;
    }
  }
  let s = (v[r] - v[0]) - (sum - (v[r] - v[0]));
  let t = (v[r-1] - v[0]) - (sum - (v[r-1] - v[0]));
  //println!("v{:?} r{} S{} T{}", v, r, s, t);
  if r - 1 == 0 || s.abs() < t.abs() { r } else { r - 1 }
}
use std::cmp::{max, min};

const INF : i64 = 100_000_000_000_000_000;
struct SegTree{v:Vec<i64>, n:usize}
impl SegTree {
  pub fn new(v : &[i64]) -> SegTree {
    let s = v.len();
    let mut m = 1; while m < s { m *= 2 }; 
    let mut d = vec![-INF; 2 * m - 1];
    for i in 0..s { d[m - 1 + i] = v[i] }
    for i in (0..m-1).rev() { d[i] = max(d[2 * i + 1], d[2 * i + 2]) }
    SegTree{v:d, n:m}
  }
  #[allow(dead_code)]
  pub fn set(&mut self, i : usize, x : i64) {
    let mut j = self.n - 1 + i;
    self.v[j] = x;
    while j > 0 {
      j = (j - 1) / 2;
      self.v[j] = max(self.v[2*j+1], self.v[2*j+2]);
    }
  }
  pub fn get(&self, l : usize, r : usize) -> i64 {
    self.getrange(l, r, 0, 0, self.n) 
  }
  fn getrange(&self, l : usize, r : usize, k : usize, a : usize, b : usize) -> i64 {
    if b <= l || r <= a { return -INF }
    if l <= a && b <= r { return self.v[k] }
    let m = (a + b) / 2;
    let ml = self.getrange(l, r, 2 * k + 1, a, m);
    let mr = self.getrange(l, r, 2 * k + 2, m, b);
    max(ml, mr)
  }
}
  
fn main() {
  input! {
    n: usize,
    a: [i64; n] 
  };
  let mut s = vec![0; n + 1];
  for i in 0..n {
    s[i + 1] = s[i] + a[i];
  }
  
  //let segmax = SegTree::new(&a);
  //let ma : Vec<i64> = a.iter().map(|x| -x).collect();
  //let segmin = SegTree::new(&ma);
  
  let mut res = INF;
  for i in 3..n {
    let l = spmin(&s[0..i]);
    let r = spmin(&s[i-1..n+1])+i-1;
    let minl = min(s[l] - s[0], s[i-1] - s[l]);
    let maxl = max(s[l] - s[0], s[i-1] - s[l]);
    let minr = min(s[r] - s[i-1], s[n] - s[r]);
    let maxr = max(s[r] - s[i-1], s[n] - s[r]);
    //println!("{} {} {} => {} {} | {} {} {} => {} {}", 0, l, i-1, minl, maxl, i-1, r, n, minr, maxr);  
    res = min(res, max(maxl, maxr) - min(minl, minr));
  }
  println!("{}", res);
}

Measured memory_bytes: 8444