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

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i = 0; i < n; i++)
#define rep2(i, x, n) for(int i = x; i <= n; i++)
#define rep3(i, x, n) for(int i = x; i >= n; i--)
#define elif else if
#define sp setprecision
#define pb(x) push_back(x)
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<int, ll> pil;
typedef pair<ll, int> pli;
typedef pair<ld, ld> pdd;
const ll MOD = 1e9+7;
//const ll MOD = 998244353;
const int inf = 1e8;
const ll INF = 1e16;
const string alpha = "abcdefghijklmnopqrstuvwxyz";

//aとbが同じ文字となりうるか判定
bool same(char a, char b){
    return (a == '?' || b == '?' || a == b);
}

//aのx文字目以降とbが一致するか
bool consist(string a, string b, int x){
    if(x >= a.size()) return true;
    rep(i, min(b.size(), a.size()-x)){
        if(!same(b[i], a[x+i])) return false;
    }
    return true;
}

//文字列sとsのi文字目(0-indexed)以降の最長共通接頭辞の長さを記録した配列を返す
vector<int> z_algorithm(string s){
    int n = s.size();
    vector<int> res(n);
    res[0] = n;
    int i = 1, j = 0;
    while(i < n){
        while(i+j < n && same(s[j], s[i+j])) j++;
        res[i] = j;
        if(j == 0) {i++; continue;}
        int k = 1;
        while(i+k < n && k+res[k] < j){
            res[i+k] = res[k];
            k++;
        }
        i += k, j -= k;
    }
    return res;
}

int main(){
    string s[3];
    int n[3];
    rep(i, 3) {cin >> s[i]; n[i] = s[i].size();}
    bool a[3][3][4001];
    rep(i, 3) rep(j, 3) rep(k, 4001){
        a[i][j][k] = consist(s[i], s[j], k);
    }
    int ans = inf;
    //先頭の文字がi,j,kの順番である場合を調べる
    rep(i, 3) rep(j, 3) rep(k, 3){
        if(i == j || j == k || k == i) continue;
        //j,kを始める位置をすべて調べる
        rep(p, n[i]+1) rep(q, max(n[j], n[i]-p)+1){
            if(!a[i][j][p] || !a[j][k][q] || !a[i][k][p+q]) continue;
            int tmp = n[i];
            tmp = max(tmp, p+n[j]);
            tmp = max(tmp, p+q+n[k]);
            ans = min(ans, tmp);
        }
    }
    cout << ans << endl;
}