Problem:
Score : 500 points

Problem Statement

Snuke has a string s.
From this string, Anuke, Bnuke, and Cnuke obtained strings a, b, and c, respectively, as follows:

Choose a non-empty (contiguous) substring of s (possibly s itself). Then, replace some characters (possibly all or none) in it with ?s.

For example, if s is mississippi, we can choose the substring ssissip and replace its 1-st and 3-rd characters with ? to obtain ?s?ssip.

You are given the strings a, b, and c.
Find the minimum possible length of s.

Constraints

1 \leq |a|, |b|, |c| \leq 2000

a, b, and c consists of lowercase English letters and ?s.

Input

Input is given from Standard Input in the following format:

a
b
c

Output

Print the minimum possible length of s.

Sample Input 1

a?c
der
cod

Sample Output 1

7

For example, s could be atcoder.

Sample Input 2

atcoder
atcoder
???????

Sample Output 2

7

a, b, and c may not be distinct.

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

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)*}
    };

    ($next:expr, mut $var:ident : $t:tt $($r:tt)*) => {
        let mut $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, [ $t:tt ]) => {
        {
            let len = read_value!($next, usize);
            (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")
    };
}

#[allow(unused_imports)]
use std::cmp::{min, max};
use std::collections::HashSet;

fn main() {
    input!{
        a: chars,
        b: chars,
        c: chars
    }
    let l = a.len();
    let m = b.len();
    let n = c.len();
    let ab = solve(&a, &b);
    let ac = solve(&a, &c);
    let bc = solve(&b, &c);
    let mut ans = l + m + n;
    for &i in ab.iter() {
        ans = min(ans, n + (max(i + m as i64, l as i64) - min(0, i)) as usize);
    }
    for &i in ac.iter() {
        ans = min(ans, m + (max(i + n as i64, l as i64) - min(0, i)) as usize);
    }
    for &i in bc.iter() {
        ans = min(ans, l + (max(i + n as i64, m as i64) - min(0, i)) as usize);
    }
    for &i in ab.iter() {
        for &j in ac.iter() {
            if j - i + n as i64 <= 0 || j - i >= m as i64 || bc.contains(&(j - i)) {
                ans = min(ans, (max(l as i64, max(i + m as i64, j + n as i64)) - min(0, min(i, j))) as usize);
            }
        }
    }
    for &i in ab.iter() {
        for &j in bc.iter() {
            if i + j + n as i64 <= 0 || i + j >= l as i64 || ac.contains(&(i + j)) {
                ans = min(ans, (max(l as i64, max(i + m as i64, i + j + n as i64)) - min(0, min(i, i + j))) as usize);
            }
        }
    }
    for &i in ac.iter() {
        for &j in bc.iter() {
            if i - j + m as i64 <= 0 || i - j >= l as i64 || ab.contains(&(i - j)) {
                ans = min(ans, (max(l as i64, max(i - j + m as i64, i + n as i64)) - min(0, min(i - j, i))) as usize);
            }
        }
    }
    println!("{}", ans);
}

fn solve(a: &Vec<char>, b: &Vec<char>) -> HashSet<i64> {
    let n = a.len();
    let m = b.len();
    let mut ret = HashSet::new();
    for i in 1..n + m {
        let mut f = true;
        for j in max(m, i)..min(n + m, i + m) {
            if a[j - m] != '?' && b[j - i] != '?' && a[j - m] != b[j - i] {
                f = false;
                break;
            }
        }
        if f {
            ret.insert(i as i64 - m as i64);
        }
    }
    ret
}