Problem:
Score : 600 points

Problem Statement

We have N strings of lowercase English letters: S_1, S_2, \cdots, S_N.

Takahashi wants to make a string that is a palindrome by choosing one or more of these strings - the same string can be chosen more than once - and concatenating them in some order of his choice.

The cost of using the string S_i once is C_i, and the cost of using it multiple times is C_i multiplied by that number of times.

Find the minimum total cost needed to choose strings so that Takahashi can make a palindrome.

If there is no choice of strings in which he can make a palindrome, print -1.

Constraints

1 \leq N \leq 50

1 \leq |S_i| \leq 20

S_i consists of lowercase English letters.

1 \leq C_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N
S_1 C_1
S_2 C_2
:
S_N C_N

Output

Print the minimum total cost needed to choose strings so that Takahashi can make a palindrome, or -1 if there is no such choice.

Sample Input 1

3
ba 3
abc 4
cbaa 5

Sample Output 1

7

We have ba, abc, and cbaa.

For example, we can use ba once and abc once for a cost of 7, then concatenate them in the order abc, ba to make a palindrome.
Also, we can use abc once and cbaa once for a cost of 9, then concatenate them in the order cbaa, abc to make a palindrome.

We cannot make a palindrome for a cost less than 7, so we should print 7.

Sample Input 2

2
abcab 5
cba 3

Sample Output 2

11

We can choose abcab once and cba twice, then concatenate them in the order abcab, cba, cba to make a palindrome for a cost of 11.

Sample Input 3

4
ab 5
cba 3
a 12
ab 10

Sample Output 3

8

We can choose a once, which is already a palindrome, but it is cheaper to concatenate ab and cba.

Sample Input 4

2
abc 1
ab 2

Sample Output 4

-1

We cannot make a palindrome, so we should print -1.

Solution in C# (.NET Core 3.1.201) (judge verdict: Wrong Answer)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Math;
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;
public static class P
{
    public static void Main()
    {
        int n = int.Parse(Console.ReadLine());
        var a = Enumerable.Repeat(0, n).Select(_ =>
        {
            var sc = Console.ReadLine().Split();
            return (sc[0], long.Parse(sc[1]));
        }).ToArray();

        var ids = new int[n][];
        var memo = new List<(int, int)>();

        int OFFSET = 0;
        for (int i = 0; i < n; i++)
        {
            ids[i] = new int[a[i].Item1.Length + 1];
            for (int j = 0; j < ids[i].Length; j++)
            {
                ids[i][j] = OFFSET++;
                memo.Add((i, j));
            }
        }

        var strAndPos = memo.ToArray();

        long[] costs = Enumerable.Repeat(long.MaxValue / 2, OFFSET * 2).ToArray();
        PriorityQueue<(int, long), long> pqueue = new PriorityQueue<(int, long), long>(x => x.Item2);

        for (int i = 0; i < n; i++)
        {
            pqueue.Push((ids[i][0], a[i].Item2));
            pqueue.Push((OFFSET + ids[i][0], a[i].Item2));
        }
        //
        //0123 4567
        while (pqueue.Count > 0)
        {
            var (id, cost) = pqueue.Pop();
            if (costs[id] < cost) continue;
            costs[id] = cost;
            bool isBackWards = OFFSET <= id;
            if (isBackWards) id -= OFFSET;
            var (sInd, pos) = strAndPos[id];
            var s = a[sInd].Item1;
            for (int tInd = 0; tInd < n; tInd++)
            {
                var t = a[tInd].Item1;
                int i, j;
                if (!isBackWards)
                {
                    for (i = pos, j = t.Length - 1; i < s.Length && j >= 0; i++, j--)
                    {
                        if (s[i] != t[j]) goto end;
                    }
                    if (s.Length - pos >= t.Length)
                    {
                        var newPos = pos + t.Length;
                        pqueue.Push((ids[sInd][newPos], cost + a[tInd].Item2));
                    }
                    else
                    {
                        var newPos = s.Length - pos;
                        pqueue.Push((ids[tInd][newPos] + OFFSET, cost + a[tInd].Item2));
                    }
                    end:;
                }
                else
                {
                    for (i = s.Length - pos - 1, j = 0; i >= 0 && j < t.Length; i--, j++)
                    {
                        if (s[i] != t[j]) goto end;
                    }

                    if (s.Length - pos >= t.Length)
                    {
                        var newPos = pos + t.Length;
                        pqueue.Push((ids[sInd][newPos] + OFFSET, cost + a[tInd].Item2));
                    }
                    else
                    {
                        var newPos = s.Length - pos;
                        pqueue.Push((ids[tInd][newPos], cost + a[tInd].Item2));
                    }
                    end:;
                }
            }
        }

        bool isPalindrome(string s)
        {
            for (int i = 0, j = s.Length - 1; i < s.Length; i++, j--)
                if (s[i] != s[j]) return false;
            return true;
        }

        var res = long.MaxValue / 2;
        for (int i = 0; i < ids.Length; i++)
        {
            var s = a[i].Item1;
            var curRes = Min(costs[ids[i][s.Length]], costs[ids[i][s.Length] + OFFSET]);
            for (int j = 0; j < s.Length; j++)
            {
                if (isPalindrome(s[j..])) curRes = Min(curRes, costs[ids[i][j]]);
                if (isPalindrome(s[..^j])) curRes = Min(curRes, costs[ids[i][j]]);
            }

            res = Min(res, curRes);
        }
        if (long.MaxValue / 2 <= res) res = -1;
        Console.WriteLine(res);
    }
}


class PriorityQueue<TValue, TKey> where TKey : IComparable<TKey>
{
    public int Count { get; private set; }
    private Func<TValue, TKey> KeySelector;
    private bool Descendance;
    private TValue[] data = new TValue[65536];
    private TKey[] keys = new TKey[65536];
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public PriorityQueue(Func<TValue, TKey> keySelector, bool descendance = false) { KeySelector = keySelector; Descendance = descendance; }
    public TValue Top
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get { ValidateNonEmpty(); return data[1]; }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public TValue Pop()
    {
        var top = Top;
        var item = data[Count];
        var key = keys[Count--];
        int index = 1;
        while (true)
        {
            if ((index << 1) >= Count)
            {
                if (index << 1 > Count) break;
                if (key.CompareTo(keys[index << 1]) > 0 ^ Descendance)
                { data[index] = data[index << 1]; keys[index] = keys[index << 1]; index <<= 1; }
                else break;
            }
            else
            {
                var nextIndex = keys[index << 1].CompareTo(keys[(index << 1) + 1]) <= 0 ^ Descendance ? (index << 1) : (index << 1) + 1;
                if (key.CompareTo(keys[nextIndex]) > 0 ^ Descendance)
                { data[index] = data[nextIndex]; keys[index] = keys[nextIndex]; index = nextIndex; }
                else break;
            }
        }
        data[index] = item;
        keys[index] = key;
        return top;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Push(TValue item)
    {
        var key = KeySelector(item);
        int index = ++Count;
        if (data.Length == Count) Extend(data.Length * 2);
        while ((index >> 1) != 0)
        {
            if (keys[index >> 1].CompareTo(key) > 0 ^ Descendance)
            { data[index] = data[index >> 1]; keys[index] = keys[index >> 1]; index >>= 1; }
            else break;
        }
        data[index] = item;
        keys[index] = key;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void Extend(int newSize)
    {
        TValue[] newData = new TValue[newSize];
        TKey[] newKeys = new TKey[newSize];
        data.CopyTo(newData, 0);
        keys.CopyTo(newKeys, 0);
        data = newData;
        keys = newKeys;
    }
    private void ValidateNonEmpty() { if (Count == 0) throw new IndexOutOfRangeException(); }
}