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# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static System.Console;
using static System.Math;

namespace AtTest.Panasonic2020
{
    class E
    {
        static void Main(string[] args)
        {
            var sw = new System.IO.StreamWriter(OpenStandardOutput()) { AutoFlush = false };
            SetOut(sw);

            Method(args);

            Out.Flush();
        }

        static void Method(string[] args)
        {
            string[] abcs = new string[3];
            abcs[0] = Read();
            abcs[1] = Read();
            abcs[2] = Read();
            int[][] pats = new int[6][];
            pats[0] = new int[3] { 0, 1, 2 };
            pats[1] = new int[3] { 0, 2, 1 };
            pats[2] = new int[3] { 1, 0, 2 };
            pats[3] = new int[3] { 1, 2, 0 };
            pats[4] = new int[3] { 2, 0, 1 };
            pats[5] = new int[3] { 2, 1, 0 };

            int res = int.MaxValue;
            for(int i = 0; i < pats.Length; i++)
            {
                string first = abcs[pats[i][0]];
                string second = abcs[pats[i][1]];
                string third = abcs[pats[i][2]];

                List<char> tmp = new List<char>();
                for (int j = 0; j < first.Length; j++)
                {
                    tmp.Add(first[j]);
                }

                int index = first.Length;
                for (int j = 0; j < first.Length; j++)
                {
                    bool ok = true;
                    for(int k = 0; k < Min(first.Length-j, second.Length); k++)
                    {
                        if (first[j + k] == '?' || second[k] == '?')
                        {
                            continue;
                        }
                        if (first[j + k] != second[k])
                        {
                            ok = false;
                            break;
                        }
                    }
                    if (ok)
                    {
                        index = j;
                        break;
                    }
                }

                for(int j = 0; j < second.Length; j++)
                {
                    if (tmp.Count > index + j)
                    {
                        if (second[j] != '?')
                        {
                            tmp[index + j] = second[j];
                        }
                    }
                    else
                    {
                        tmp.Add(second[j]);
                    }
                }

                index = tmp.Count;
                for (int j = 0; j < tmp.Count; j++)
                {
                    bool ok = true;
                    for (int k = 0; k < Min(tmp.Count - j, third.Length); k++)
                    {
                        if (tmp[j + k] == '?' || third[k] == '?')
                        {
                            continue;
                        }
                        if (tmp[j + k] != third[k])
                        {
                            ok = false;
                            break;
                        }
                    }
                    if (ok)
                    {
                        index = j;
                        break;
                    }
                }

                for (int j = 0; j < third.Length; j++)
                {
                    if (tmp.Count > index + j)
                    {
                        if (third[j] != '?')
                        {
                            tmp[index + j] = third[j];
                        }
                    }
                    else
                    {
                        tmp.Add(third[j]);
                    }
                }
                res = Min(res, tmp.Count);
            }
            WriteLine(res);
        }

        class RollingHash2
        {
            long mod = 1000000007;
            long[] bases = new long[3] { 1009, 2003, 3001 };
            long[,] pows;
            long[,] hashes;

            public RollingHash2(long[] array)
            {
                pows = new long[array.Length, bases.Length];
                for (int i = 0; i < array.Length; i++)
                {
                    for (int j = 0; j < bases.Length; j++)
                    {
                        if (i == 0) pows[i, j] = 1;
                        else pows[i, j] = (pows[i - 1, j] * bases[j]) % mod;
                    }
                }

                hashes = new long[array.Length, bases.Length];
                for (int i = 0; i < array.Length; i++)
                {
                    for (int j = 0; j < bases.Length; j++)
                    {
                        if (i > 0) hashes[i, j] = (hashes[i - 1, j] * bases[j]) % mod;
                        hashes[i, j] += array[i];
                        hashes[i, j] %= mod;
                    }
                }
            }

            public long[] GetRangeHash(int l, int length)
            {
                long[] hash = new long[bases.Length];
                for (int i = 0; i < bases.Length; i++)
                {
                    hash[i] = hashes[l + length - 1, i];
                    if (l > 0)
                    {
                        hash[i] += mod - (hashes[l - 1, i] * pows[length, i]) % mod;
                        hash[i] %= mod;
                    }
                }
                return hash;
            }

            public bool ValidateRange(int l, int length, long[] hash)
            {
                int r = l + length - 1;
                long[] rangeHash = GetRangeHash(l, length);
                for (int i = 0; i < bases.Length; i++)
                {
                    if (rangeHash[i] != hash[i]) return false;
                }
                return true;
            }

            public long[] CalcHash(long[] s)
            {
                long[] vals = new long[bases.Length];
                for (int i = 0; i < s.Length; i++)
                {
                    for (int j = 0; j < bases.Length; j++)
                    {
                        vals[j] = (vals[j] * bases[j] + s[i]) % mod;
                    }
                }
                return vals;
            }
        }

        private static string Read() { return ReadLine(); }
        private static char[] ReadChars() { return Array.ConvertAll(Read().Split(), a => a[0]); }
        private static int ReadInt() { return int.Parse(Read()); }
        private static long ReadLong() { return long.Parse(Read()); }
        private static double ReadDouble() { return double.Parse(Read()); }
        private static int[] ReadInts() { return Array.ConvertAll(Read().Split(), int.Parse); }
        private static long[] ReadLongs() { return Array.ConvertAll(Read().Split(), long.Parse); }
        private static double[] ReadDoubles() { return Array.ConvertAll(Read().Split(), double.Parse); }
    }
}