Problem:
Score : 500 points

Problem Statement

We have a deck consisting of N cards. Each card has an integer written on it. The integer on the i-th card from the top is a_i.

Two people X and Y will play a game using this deck. Initially, X has a card with Z written on it in his hand, and Y has a card with W written on it in his hand. Then, starting from X, they will alternately perform the following action:

Draw some number of cards from the top of the deck. Then, discard the card in his hand and keep the last drawn card instead. Here, at least one card must be drawn.

The game ends when there is no more card in the deck. The score of the game is the absolute difference of the integers written on the cards in the two players' hand.

X will play the game so that the score will be maximized, and Y will play the game so that the score will be minimized. What will be the score of the game?

Constraints

All input values are integers.

1 \leq N \leq 2000

1 \leq Z, W, a_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N Z W
a_1 a_2 ... a_N

Output

Print the score.

Sample Input 1

3 100 100
10 1000 100

Sample Output 1

900

If X draws two cards first, Y will draw the last card, and the score will be |1000 - 100| = 900.

Sample Input 2

3 100 1000
10 100 100

Sample Output 2

900

If X draws all the cards first, the score will be |1000 - 100| = 900.

Sample Input 3

5 1 1
1 1 1 1 1

Sample Output 3

0

Sample Input 4

1 1 1
1000000000

Sample Output 4

999999999

Solution in Rust (1.15.1) (judge verdict: Accepted)

use std::cmp;
use std::cmp::Ordering;
use std::fmt::Debug;
#[allow(unused_imports)]
use std::fs::File;
#[allow(unused_imports)]
use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
use std::ops::Range;
use std::str::FromStr;

macro_rules! debug {
    ($($a:expr), *) => {
        writeln!(
            std::io::stderr(),
            concat!($(stringify!($a), " = {:?}, "),*), $($a),*
        ).unwrap();
    }
}

pub fn start<R: Read, W: Write>(input: R, output: &mut W) {
    let mut scanner = Scanner::new(input.bytes().map(Result::unwrap));
    let n = scanner.next_value::<usize>();
    let z = scanner.next_value::<isize>();
    let w = scanner.next_value::<isize>();
    let arr = scanner.next_array::<isize>(n);

    let mut dp = vec![vec![0; n]; 2];
    for i in (0..n).rev() {
        let zn = if i == 0 { z } else { arr[i - 1] };
        let wn = if i == 0 { w } else { arr[i - 1] };
        dp[0][i] = ((i + 1)..n)
            .map(|j| dp[1][j])
            .fold((wn - arr[n - 1]).abs(), |x, y| cmp::max(x, y));
        dp[1][i] = ((i + 1)..n)
            .map(|j| dp[0][j])
            .fold((zn - arr[n - 1]).abs(), |x, y| cmp::min(x, y));
    }

    writeln!(output, "{}", dp[0][0]).unwrap();
}

////////////////////////////
// Snipetts
////////////////////////////

#[allow(dead_code)]
fn main() {
    let stdin = stdin();
    let stdout = stdout();
    let mut out = BufWriter::new(stdout.lock());
    let input = BufReader::new(stdin.lock());
    start(input, &mut out);
}

// // ファイルの場合
// #[allow(dead_code)]
// fn main() {
//     let mut out = BufWriter::new(File::create("output.txt").unwrap());
//     let input = BufReader::new(File::open("input.txt").unwrap());
//     start(input, &mut out);
// }

// 大きなスタックが必要な場合はこちらを利用する
// #[allow(dead_code)]
// fn main() {
//     std::thread::Builder::new()
//         .name("big stack size".into())
//         .stack_size(32 * 1024 * 1024) // 32 MBのスタックサイズ
//         .spawn(|| {
//             let stdin = stdin();
//             let stdout = stdout();
//             let out = BufWriter::new(stdout.lock());
//             let input = BufReader::new(stdin.lock());
//             start(input, out);
//         })
//         .unwrap()
//         .join()
//         .unwrap();
// }

pub struct Scanner<I: Iterator<Item = u8>> {
    input: I,
}

impl<I: Iterator<Item = u8>> Scanner<I> {
    pub fn new(input: I) -> Self {
        Scanner::<I> { input: input }
    }

    // 文字コードはISO/IEC 8859-1 (Latin-1)とする
    pub fn next_value<T: FromStr>(&mut self) -> T
    where
        <T as FromStr>::Err: Debug,
    {
        T::from_str(
            &(self
                .input
                .by_ref()
                .map(char::from)
                .skip_while(|x| x.is_whitespace())
                .take_while(|x| !x.is_whitespace())
                .collect::<String>()),
        )
        .unwrap()
    }

    // 文字コードはISO/IEC 8859-1 (Latin-1)とする
    #[allow(dead_code)]
    pub fn next_bytes(&mut self) -> Vec<u8> {
        self.input
            .by_ref()
            .skip_while(|&x| char::from(x).is_whitespace())
            .take_while(|&x| !char::from(x).is_whitespace())
            .collect::<Vec<_>>()
    }

    #[allow(dead_code)]
    pub fn next_array<T: FromStr>(&mut self, len: usize) -> Vec<T>
    where
        <T as FromStr>::Err: Debug,
    {
        (0..len).map(|_| self.next_value()).collect()
    }

    #[allow(dead_code)]
    pub fn next_2darray<T: FromStr>(&mut self, x: usize, y: usize) -> Vec<Vec<T>>
    where
        <T as FromStr>::Err: Debug,
    {
        (0..y).map(|_| self.next_array(x)).collect()
    }

    #[allow(dead_code)]
    pub fn next_2d_bytes(&mut self, len: usize) -> Vec<Vec<u8>> {
        (0..len).map(|_| self.next_bytes()).collect()
    }
}

// 1.15.1でReverseを使う
// https://qiita.com/hatoo@github/items/fa14ad36a1b568d14f3e
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Reverse<T>(pub T);

impl<T: PartialOrd> PartialOrd for Reverse<T> {
    fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Reverse<T> {
    fn cmp(&self, other: &Reverse<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

// PartialOrdをTotalOrdにするラッパ
// https://qiita.com/hatoo@github/items/fa14ad36a1b568d14f3e

#[derive(PartialEq, PartialOrd)]
pub struct Total<T>(pub T);

impl<T: PartialEq> Eq for Total<T> {}

impl<T: PartialOrd> Ord for Total<T> {
    fn cmp(&self, other: &Total<T>) -> Ordering {
        self.0.partial_cmp(&other.0).unwrap()
    }
}

// 順列生成
#[allow(dead_code)]
pub fn permutations<'a, T: 'a + From<u8> + Clone + PartialEq + Sized>(
    n: T,
    k: usize,
) -> Box<Iterator<Item = Vec<T>> + 'a>
where
    Range<T>: Iterator<Item = T>,
{
    fn inner<'a, T: 'a + From<u8> + Clone + PartialEq + Sized>(
        array: Vec<T>,
        depth: usize,
        max: T,
    ) -> Box<Iterator<Item = Vec<T>> + 'a>
    where
        Range<T>: Iterator<Item = T>,
    {
        let na = (T::from(0)..max.clone()).flat_map(move |x| {
            if array.contains(&x) {
                None
            } else {
                let mut newarray = array.clone();
                newarray.push(x);
                Some(newarray)
            }
        });
        if depth > 0 {
            Box::new(na.flat_map(move |x| inner(x, depth - 1, max.clone())))
        } else {
            Box::new(na)
        }
    }
    inner(Vec::new(), k - 1, n)
}

// 組み合わせ生成
#[allow(dead_code)]
pub fn combinations(n: usize, r: usize) -> Box<Iterator<Item = Vec<u8>>> {
    fn inner(
        array: Vec<u8>,
        depth: usize,
        min: usize,
        max: usize,
    ) -> Box<Iterator<Item = Vec<u8>>> {
        let na = (min..(max - depth)).map(move |x| {
            let mut newarray = array.clone();
            newarray.push(x as u8);
            newarray
        });
        if depth > 0 {
            Box::new(na.flat_map(move |x| {
                let next = usize::from(*x.last().unwrap()) + 1;
                inner(x, depth - 1, next, max)
            }))
        } else {
            Box::new(na)
        }
    }
    inner(Vec::new(), r - 1, 0, n)
}

#[derive(Copy)]
struct AhoCorasickState {
    next: [usize; 256],
}

impl Clone for AhoCorasickState {
    fn clone(&self) -> AhoCorasickState {
        AhoCorasickState { next: self.next }
    }
}

impl AhoCorasickState {
    fn new() -> AhoCorasickState {
        AhoCorasickState { next: [0; 256] }
    }

    fn set_next(&mut self, index: usize, value: usize) {
        self.next[index] = value;
    }

    fn get_next(&self, index: usize) -> Option<usize> {
        if self.next[index] != 0 {
            Some(self.next[index])
        } else {
            None
        }
    }

    fn keys(&self) -> Vec<usize> {
        self.next
            .iter()
            .enumerate()
            .filter(|&(_, &y)| y != 0)
            .map(|(y, _)| y)
            .collect::<Vec<_>>()
    }
}

#[allow(dead_code)]
pub struct AhoCorasickAutomaton {
    states: Vec<AhoCorasickState>,
    failure_link: Vec<usize>,
    output: Vec<Vec<Vec<u8>>>,
}

impl AhoCorasickAutomaton {
    pub fn new(terms: &[Vec<u8>]) -> AhoCorasickAutomaton {
        let mut result = AhoCorasickAutomaton {
            states: vec![AhoCorasickState::new()],
            failure_link: Vec::new(),
            output: vec![Vec::new()],
        };
        result.make_trie(terms);
        result.make_failure();
        result
    }

    fn make_trie(&mut self, terms: &[Vec<u8>]) {
        for term in terms {
            let mut current = 0;
            for &c in term {
                let next_key = usize::from(c);
                current = if let Some(next) = self.states[current].get_next(next_key) {
                    next
                } else {
                    let next = self.states.len();
                    self.states.push(AhoCorasickState::new());
                    self.states[current].set_next(next_key, next);
                    self.output.push(Vec::new());
                    next
                };
            }
            self.output[current].push(term.clone());
        }
    }

    fn make_failure(&mut self) {
        let mut failure = vec![0; self.states.len()];
        let mut queue = vec![0];
        while let Some(s) = queue.pop() {
            for x in self.states[s].keys() {
                if let Some(next) = self.g(s, x) {
                    queue.push(next);
                    if s != 0 {
                        let mut f = failure[s];
                        while let None = self.g(f, x) {
                            f = failure[f];
                        }
                        failure[next] = self.g(f, x).unwrap();
                        let mut n = self.output[failure[next]].clone();
                        self.output[next].append(&mut n);
                    }
                }
            }
        }
        self.failure_link = failure;
    }

    fn g(&self, s: usize, x: usize) -> Option<usize> {
        if let Some(r) = self.states[s].get_next(x) {
            Some(r)
        } else if s == 0 {
            Some(0)
        } else {
            None
        }
    }

    pub fn match_iter<'a>(&'a self, query: &'a [u8]) -> AhoCorasickAutomatonMatcher<'a> {
        AhoCorasickAutomatonMatcher {
            index: 0,
            state: 0,
            sindex: 0,
            ac: self,
            query: query,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct MatchValue<'a> {
    pub start: usize,
    pub end: usize,
    pub value: &'a [u8],
}

pub struct AhoCorasickAutomatonMatcher<'a> {
    index: usize,
    state: usize,
    sindex: usize,
    ac: &'a AhoCorasickAutomaton,
    query: &'a [u8],
}

impl<'a> Iterator for AhoCorasickAutomatonMatcher<'a> {
    type Item = MatchValue<'a>;

    fn next(&mut self) -> Option<MatchValue<'a>> {
        loop {
            if let Some(r) = self.ac.output[self.state].get(self.sindex) {
                self.sindex += 1;
                return Some(MatchValue {
                    start: self.index - r.len(),
                    end: self.index - 1,
                    value: &r,
                });
            }

            self.sindex = 0;
            if let Some(&c) = self.query.get(self.index) {
                self.index += 1;
                let c = usize::from(c);
                while let None = self.ac.g(self.state, c) {
                    self.state = self.ac.failure_link[self.state];
                }
                self.state = self.ac.g(self.state, c).unwrap();
            } else {
                return None;
            }
        }
    }
}

// Sunday's
pub struct QuickSearchTable {
    table: [usize; 256],
    output: Vec<u8>,
}

impl QuickSearchTable {
    pub fn new(term: &[u8]) -> QuickSearchTable {
        let mut r = [term.len() + 1; 256];
        for (i, &c) in term.iter().enumerate() {
            r[usize::from(c)] = term.len() - i;
        }
        QuickSearchTable {
            table: r,
            output: term.to_vec(),
        }
    }

    pub fn match_iter<'a>(&'a self, query: &'a [u8]) -> QuickSearchMatcher<'a> {
        QuickSearchMatcher {
            index: 0,
            qst: self,
            query: query,
        }
    }
}

pub struct QuickSearchMatcher<'a> {
    index: usize,
    qst: &'a QuickSearchTable,
    query: &'a [u8],
}

impl<'a> Iterator for QuickSearchMatcher<'a> {
    type Item = MatchValue<'a>;

    fn next(&mut self) -> Option<MatchValue<'a>> {
        while self.index + self.qst.output.len() <= self.query.len() {
            let mut j = 0;
            while j < self.qst.output.len() {
                if self.qst.output[j] != self.query[self.index + j] {
                    break;
                }
                j += 1;
            }
            let before_index = self.index;
            self.index += self
                .query
                .get(self.index + self.qst.output.len())
                .and_then(|&x| self.qst.table.get(usize::from(x)))
                .map_or_else(|| self.qst.output.len() + 1, |&x| x);

            if j == self.qst.output.len() {
                return Some(MatchValue {
                    start: before_index,
                    end: before_index + self.qst.output.len() - 1,
                    value: &self.qst.output,
                });
            }
        }
        None
    }
}

pub trait ChainedOrdering {
    fn then(self, other: Ordering) -> Ordering;
    fn and_then<F: FnOnce() -> Ordering>(self, other: F) -> Ordering;
}

impl ChainedOrdering for Ordering {
    fn then(self, other: Ordering) -> Ordering {
        match self {
            Ordering::Equal => other,
            o => o,
        }
    }

    fn and_then<F: FnOnce() -> Ordering>(self, other: F) -> Ordering {
        match self {
            Ordering::Equal => other(),
            o => o,
        }
    }
}

pub trait Lis {
    type Item;

    fn lis_by<F: FnMut(&Self::Item, &Self::Item) -> Ordering>(&self, f: F) -> usize;
    fn lis(&self) -> usize
    where
        Self::Item: Ord;
    fn lis_by_key<T: Ord, F: FnMut(&Self::Item) -> T>(&self, f: F) -> usize;
}

impl<T> Lis for [T] {
    type Item = T;

    fn lis_by<F: FnMut(&T, &T) -> Ordering>(&self, mut f: F) -> usize {
        let mut result = Vec::new();
        for c in self {
            if let Err(s) = result.binary_search_by(|&x| f(x, c)) {
                if s == result.len() {
                    result.push(c);
                } else {
                    result[s] = c;
                }
            }
        }
        result.len()
    }

    fn lis(&self) -> usize
    where
        T: Ord,
    {
        self.lis_by(|a, b| a.cmp(b))
    }

    fn lis_by_key<K: Ord, F: FnMut(&Self::Item) -> K>(&self, mut f: F) -> usize {
        self.lis_by(|a, b| f(a).cmp(&f(b)))
    }
}

pub fn mod_pow(mut base: usize, mut pow: usize, modu: usize) -> usize {
    let mut result = 1;
    while pow > 0 {
        if (pow & 1) == 1 {
            result = (result * base) % modu;
        }
        pow >>= 1;
        base = (base * base) % modu;
    }
    result
}

const MIRROR_RABIN_BASE_32: &'static [usize] = &[2, 7, 61];
#[cfg(target_pointer_width = "64")]
const MIRROR_RABIN_BASE_64: &'static [usize] =
    &[2, 325, 9_375, 28_178, 450_775, 9_780_504, 1_795_265_022];

#[cfg(target_pointer_width = "32")]
fn miller_rabin_base(n: usize) -> &'static [usize] {
    MIRROR_RABIN_BASE_32
}

#[cfg(target_pointer_width = "64")]
fn miller_rabin_base(n: usize) -> &'static [usize] {
    match n {
        0...4_759_123_142 => MIRROR_RABIN_BASE_32,
        _ => MIRROR_RABIN_BASE_64,
    }
}

// Miller–Rabin primality test
pub fn is_prime(n: usize) -> bool {
    if n == 2 {
        return true;
    }

    if n == 1 || (n & 1) == 0 {
        return false;
    }

    let mut d = n - 1;
    let s = d.trailing_zeros();
    d >>= s;

    'outer: for &b in miller_rabin_base(n) {
        if b == n {
            continue;
        }
        let mut c = mod_pow(b, d, n);
        if c == 1 {
            continue;
        }
        for _ in 0..s {
            if c == n - 1 {
                continue 'outer;
            }
            c = (c * c) % n;
        }
        return false;
    }
    true
}

pub fn gcd(mut m: usize, mut n: usize) -> usize {
    if m == 0 || n == 0 {
        return m | n;
    }
    let shift = (m | n).trailing_zeros();

    n >>= n.trailing_zeros();

    while m != 0 {
        m >>= m.trailing_zeros();
        if n > m {
            ::std::mem::swap(&mut n, &mut m)
        }
        m -= n;
    }
    n << shift
}

pub fn prime_factorization(n: usize) -> PrimeFactorIterator {
    PrimeFactorIterator(n)
}

pub struct PrimeFactorIterator(usize);

impl Iterator for PrimeFactorIterator {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        if self.0 == 0 {
            return None;
        }

        let result = if self.0 == 1 {
            1
        } else {
            factorization(self.0)
        };

        self.0 /= result;
        if self.0 == 1 {
            self.0 = 0;
        }
        Some(result)
    }
}

// Pollard's rho algorithm
fn factorization(n: usize) -> usize {
    if (n & 1) == 0 {
        return 2;
    }
    if is_prime(n) {
        return n;
    }

    fn f(x: usize, n: usize, i: usize) -> usize {
        ((((i + 1) * 4) + 1) * x) % n
    }

    let mut i = 0;
    loop {
        let mut x = 2;
        let mut y = 2;
        let mut d = 1;

        while d == 1 {
            x = f(x, n, i);
            y = f(f(y, n, i), n, i);
            d = gcd(if x > y { x - y } else { y - x }, n);
        }
        // 本当はメモ化しておくのがよいと思う
        if d != n {
            return factorization(d);
        }
        i += 1;
    }
}

pub fn mod_inv(n: u64, base: u64) -> u64 {
    let mut now = (0, 1, base);
    let mut prev = (1, 0, n % base);

    while now.2 > 0 {
        let q = (prev.2 / now.2) as u64;

        let next = (
            (prev.0 + (base - now.0) * q) % base,
            (prev.1 + (base - now.1) * q) % base,
            prev.2 - q * now.2,
        );
        prev = ::std::mem::replace(&mut now, next);
    }
    prev.0
}

pub fn max_by_key<T, U: Ord, F: Fn(&T) -> U>(a: T, b: T, selector: F) -> T {
    if selector(&a).cmp(&selector(&b)) != Ordering::Less {
        a
    } else {
        b
    }
}

pub fn min_by_key<T, U: Ord, F: Fn(&T) -> U>(a: T, b: T, selector: F) -> T {
    if selector(&a).cmp(&selector(&b)) != Ordering::Greater {
        a
    } else {
        b
    }
}