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++ (GCC 9.2.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define m_p make_pair

namespace IO {
    #define gc getchar()
    template <typename T>
    inline void read(T& x) {
        x = 0; bool f = 1; char ch;
        for (ch = gc; ch < '0' || '9' < ch; ch = gc) if (ch == '-') f ^= 1;
        for (; '0' <= ch && ch <= '9'; ch = gc) x = (x << 3) + (x << 1) + (ch ^ 48);
        x = f ? x : -x;
    }
    #undef gc
}

typedef long long ll;

const int MAXN = 2000 + 10;

template <typename T>
bool chkmin(T& a, T b) { if (a > b) return a = b, true; return false; }
template <typename T>
bool chkmax(T& a, T b) { if (a < b) return a = b, true; return false; }

int n;
string str[MAXN], id_to_str[MAXN];
bool is_palindrome[MAXN];
unordered_map<string, int> str_to_id;
ll val[MAXN], ans = LONG_LONG_MAX, dis[2][MAXN], vis[2][MAXN];

typedef pair<int, int> Node;
typedef pair<ll, Node > plii;

priority_queue<plii, vector<plii>, greater<plii> > que;

bool starts_with(string& a, string& b) {
    if (a.size() < b.size()) return false;
    rep(i, 0, b.size() - 1) if (a[i] != b[i]) return false;
    return true;
}

Node trans(int flg, string u, string v) {
    Node ret; ret.first = 0, ret.second = 0;
    string res;
    if (flg == 0) reverse(v.begin(), v.end()), res = u;
    else reverse(u.begin(), u.end()), res = v;
    if (flg == 0 && starts_with(u, v) || flg == 1 && starts_with(v, u)) {
        ret.first = 0;
        if (flg == 1) res = v.substr(u.size(), v.size() - u.size() + 1);
        else res = u.substr(v.size(), u.size() - v.size() + 1);
    } else if (flg == 0 && starts_with(v, u) || flg == 1 && starts_with(u, v)) {
        ret.first = 1;
        if (flg == 0) res = v.substr(u.size(), v.size() - u.size() + 1);
        else res = u.substr(v.size(), u.size() - v.size() + 1);
        reverse(res.begin(), res.end());
    } else {
        ret.first = -1;
        return ret;
    }
    ret.second = str_to_id[res];
    return ret;
}

int main() {
    IO::read(n);
    str_to_id[""] = 0;
    rep(i, 1, n) {
        cin >> str[i]; IO::read(val[i]);
        string cur; cur.clear();
        rep(j, 0, str[i].size() - 1) {
            cur.push_back(str[i][j]);
            if (!str_to_id.count(cur)) {
                int _sz = str_to_id.size();
                str_to_id[cur] = _sz;
            }
        }
        cur.clear();
        per(j, str[i].size() - 1, 0) {
            cur.push_back(str[i][j]);
            if (!str_to_id.count(cur)) {
                int _sz = str_to_id.size();
                str_to_id[cur] = _sz;
            }
        }
    }
    for (auto _cur : str_to_id) {
        string cur = _cur.first;
        string ruc = cur;
        id_to_str[_cur.second] = cur;
        reverse(ruc.begin(), ruc.end());
        is_palindrome[_cur.second] = (cur == ruc);
    }
    rep(i, 0, str_to_id.size()) dis[0][i] = dis[1][i] = LONG_LONG_MAX >> 1;
    rep(i, 1, n) {
        if (is_palindrome[str_to_id[str[i]]]) ans = min(ans, val[i]);
        chkmin(dis[0][str_to_id[str[i]]], val[i]);
        chkmin(dis[1][str_to_id[str[i]]], val[i]);
        que.push(m_p(val[i], m_p(0, str_to_id[str[i]])));
        que.push(m_p(val[i], m_p(1, str_to_id[str[i]])));
    }
    while (!que.empty()) {
        plii u = que.top(); que.pop();
        if (vis[u.second.first][u.second.second]) continue;
        vis[u.second.first][u.second.second] = true;
        rep(i, 1, n) {
            Node v = trans(u.second.first, id_to_str[u.second.second], str[i]);
            if (v.first == -1) continue;
            if (chkmin(dis[v.first][v.second], dis[u.second.first][u.second.second] + val[i])) {
                que.push(m_p(dis[v.first][v.second], v));
            }
        }
    }
    rep(i, 0, str_to_id.size()) {
        if (is_palindrome[i]) chkmin(ans, min(dis[0][i], dis[1][i]));
    }
    if (ans >= (LONG_LONG_MAX >> 1)) { puts("-1"); return 0; }
    printf("%lld\n", ans);
    return 0;
}