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 SZ(x) (int)(x.size())
#define REP(i, n) for(int i=0;i<(n);++i)
#define FOR(i, a, b) for(int i=(a);i<(b);++i)
#define RREP(i, n) for(int i=(int)(n);i>=0;--i)
#define RFOR(i, a, b) for(int i=(int)(a);i>=(int)(b);--i)
#define ALL(a) (a).begin(),(a).end()
#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<< endl;

using ll = long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using P = pair<int, int>;

const double eps = 1e-8;
const ll MOD = 1000000007;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;

template<typename T1, typename T2>
bool chmax(T1 &a, const T2 &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template<typename T1, typename T2>
bool chmin(T1 &a, const T2 &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template<typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> p) {
  os << p.first << ":" << p.second;
  return os;
}

template<class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  REP(i, SZ(v)) {
    if (i) os << " ";
    os << v[i];
  }
  return os;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  int n;
  cin >> n;
  vector<string> s(n);
  vector<ll> c(n);
  REP(i, n) cin >> s[i] >> c[i];

  using elm = pair<ll, pair<int, string>>;
  vector<map<string, ll>> d(2, map<string, ll>());
  priority_queue<elm, vector<elm>, greater<elm>> pq;

  REP(j, n) {
    d[0][s[j]] = c[j];
    pq.push({c[j], {0, s[j]}});
  }

  while (!pq.empty()) {
    auto now = pq.top();
    pq.pop();
    ll val = now.first;
    int isl = now.second.first;
    string nows = now.second.second;

    if (val > d[isl][nows]) continue;

    REP(i, n) {
      bool ok = true;
      string tmps = s[i];
      if (!isl) reverse(ALL(tmps));
      REP(j, min(SZ(nows), SZ(tmps))) {
        ok &= tmps[j] == nows[j];
      }
      if (!ok) continue;


      if (SZ(nows) > SZ(tmps)) {
        string nxts = nows.substr(SZ(tmps), SZ(nows) - SZ(tmps));
        //cout << nxts << endl;
        ll nxtval = val + c[i];
        if (d[isl].find(nxts) == d[isl].end() || d[isl][nxts] > nxtval) {
          d[isl][nxts] = nxtval;
          pq.push({nxtval, {isl, nxts}});
        }
      } else if (SZ(nows) < SZ(tmps)) {
        string nxts = tmps.substr(SZ(nows), SZ(tmps) - SZ(nows));
        //cout << nxts << endl;
        ll nxtval = val + c[i];
        if (d[!isl].find(nxts) == d[!isl].end() || d[!isl][nxts] > nxtval) {
          d[!isl][nxts] = nxtval;
          pq.push({nxtval, {!isl, nxts}});
        }
      } else {
        ll nxtval = val + c[i];
          if (d[isl].find("") == d[isl].end() || d[isl][""] > nxtval) {
            d[isl][""] = nxtval;
            pq.push({nxtval, {isl, ""}});
          }
      }
    }
  }

  ll ans = LLONG_MAX;
  REP(i, 2) {
    for (auto &e: d[i]) {
      //cout << i << ":" << e << endl;
      string tmp = e.first;
      ll val = e.second;
      bool ispal = true;
      REP(j, SZ(tmp) / 2) {
        ispal &= tmp[j] == tmp[SZ(tmp) - 1 - j];
      }
      if (!ispal) continue;
      chmin(ans, val);
    }
  }
  cout << (ans == LLONG_MAX ? -1 : ans) << endl;


}