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

use std::io::*;
use std::str::FromStr;
use std::cmp;

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

/*
　0-originの配列の、i番目からj-1番目までの数列の和
 */
fn section_sum(cumsum: &Vec<i64>, i: usize, j: usize) -> i64 {
    let ans = match j - i > 0 {
        true => cumsum[j] - cumsum[i],
        false => cumsum[i] - cumsum[j],
    };
    ans
}

fn main() {
    let n = read::<i64>();
    let mut a = vec![0; n as usize];
    let mut cumsum = vec![0; (n + 1) as usize];
    for i in 0..n {
        a[i as usize] = read::<i64>();
        cumsum[(i+1) as usize] = cumsum[i as usize] + a[i as usize];
    }
    //println!("{:?}", a);
    //println!("{:?}", cumsum);
    //println!("{}", section_sum(&cumsum, 0, 3));
    // 真ん中の仕切りを固定した時の左側配列の切れ目
    // i番目とi+1番目の間で仕切る→leftにはi+1が入る
    let mut left: Vec<i64> = Vec::new();
    //println!("left : {:?}", left);
    let mut right: Vec<i64> = Vec::new();
    let mut l1 = 0;
    let mut l2 = 0;
    let mut r1 = 0;
    let mut r2 = 0;
    let mut ans = 100000000000;
    // i-1とiの間で切る
    for i in 2..n-1 {
        // 左の仕切りは単調増加
        let mut new_left = 1;
        if left.len() > 0 {
            new_left = left[left.len() - 1];
        }
        let mut sum1 = section_sum(&cumsum, 0, new_left as usize);
        //println!("{:?}", sum1);
        let mut sum2 = section_sum(&cumsum, new_left as usize, i as usize);
        let mut diff = (sum2-sum1).abs();
        //println!("{:?}", sum2);
        loop {
            //println!("{}", new_left);
            sum1 = section_sum(&cumsum, 0, (new_left+1) as usize);
            sum2 = section_sum(&cumsum, (new_left+1) as usize, i as usize);
            if diff  < (sum2-sum1).abs() {
                break;
            } 
            //println!("{}", sum1);
            //println!("{}", sum2);
            diff = (sum2-sum1).abs();
            new_left += 1;
        }
        l1 = section_sum(&cumsum, 0, new_left as usize);
        l2 = section_sum(&cumsum, new_left as usize, i as usize);
        left.push(new_left);
        //println!("{} {}", new_left, i);
        let mut new_right = i + 1;
        if right.len() > 0 {
            new_right = right[right.len() - 1];
        }
        let mut sum1 = section_sum(&cumsum, i as usize, new_right as usize);
        //println!("{:?}", sum1);
        let mut sum2 = section_sum(&cumsum, new_right as usize, n as usize);
        let mut diff = (sum2-sum1).abs();
        //println!("{:?}", sum2);
        loop {
            //println!("{}", new_left);
            sum1 = section_sum(&cumsum, i as usize, (new_right+1) as usize);
            sum2 = section_sum(&cumsum, (new_right+1) as usize, n as usize);
            if diff  < (sum2-sum1).abs() {
                break;
            } 
            //println!("{}", sum1);
            //println!("{}", sum2);
            diff = (sum2-sum1).abs();
            new_right += 1;
        }
        right.push(new_right);
        r1 = section_sum(&cumsum, i as usize, new_right as usize);
        r2 = section_sum(&cumsum, new_right as usize, n as usize);
        let tmp = cmp::max(cmp::max(l1,l2), cmp::max(r1,r2)) - cmp::min(cmp::min(l1,l2), cmp::min(r1,r2));
        ans = cmp::min(ans, tmp);
        //println!("{} {}", new_right, i);
    }
    //println!("left : {:?}", left);
    //println!("right : {:?}", right);
    println!("{}", ans);
}