// ---------- begin chmin, chmax ----------
trait ChangeMinMax {
    fn chmin(&mut self, x: Self) -> bool;
    fn chmax(&mut self, x: Self) -> bool;
}

impl<T: PartialOrd> ChangeMinMax for T {
    fn chmin(&mut self, x: Self) -> bool {
        *self > x && {
            *self = x;
            true
        }
    }
    fn chmax(&mut self, x: Self) -> bool {
        *self < x && {
            *self = x;
            true
        }
    }
}
// ---------- end chmin, chmax ----------

use proconio::*;
use proconio::marker::*;
use std::cmp::*;

fn is_palindrome<T: Eq>(s: &[T]) -> bool {
    s.iter().zip(s.iter().rev()).all(|p| *p.0 == *p.1)
}

fn lcp<T: Eq>(a: &[T], b: &[T]) -> usize {
    a.iter().zip(b.iter()).take_while(|p| *p.0 == *p.1).count()
}

fn run() {
    input! {
        n: usize,
        ask: [(Bytes, u64); n],
    }
    let mut a = vec![];
    let mut b = vec![];
    let mut c = vec![];
    for (s, w) in ask {
        a.push(s.clone());
        let mut s = s;
        s.reverse();
        b.push(s);
        c.push(w);
    }
    let w = 21;
    let mut graph = vec![vec![]; n * 2 * w + 1];
    let src = graph.len() - 1;
    for (i, (x, (y, &z))) in a.iter().zip(b.iter().zip(c.iter())).enumerate() {
        if is_palindrome(x) {
            graph[src].push((src, z));
        } else {
            let len = x.len();
            graph[src].push((i * w * 2 + len, z));
            graph[src].push((i * w * 2 + w + len, z));
        }
        for (j, (p, (q, &r))) in a.iter().zip(b.iter().zip(c.iter())).enumerate() {
            for k in 1..=x.len() {
                let (x, y) = (&x[(x.len() - k)..], &y[(y.len() - k)..]);
                let n = lcp(x, q);
                let m = min(x.len(), q.len());
                if m == n {
                    let x = &x[n..];
                    let q = &q[n..];
                    let v = i * w * 2 + k;
                    if is_palindrome(x) && is_palindrome(q) {
                        graph[v].push((src, r));
                    } else if !x.is_empty() {
                        graph[v].push((i * w * 2 + x.len(), r));
                    } else {
                        graph[v].push((j * w * 2 + w + q.len(), r));
                    }
                }
                let n = lcp(y, p);
                let m = min(y.len(), p.len());
                if m == n {
                    let y = &y[n..];
                    let p = &p[n..];
                    let v = i * w * 2 + w + k;
                    if is_palindrome(y) && is_palindrome(p) {
                        graph[v].push((src, r));
                    } else if !y.is_empty() {
                        graph[v].push((i * w * 2 + w + y.len(), r));
                    } else {
                        graph[v].push((j * w * 2 + p.len(), r));
                    }
                }
            }
        }
    }
    let mut dp = vec![std::u64::MAX; graph.len()];
    let mut h = std::collections::BinaryHeap::new();
    for &(u, c) in graph[src].iter() {
        if dp[u].chmin(c) {
            h.push(Reverse((c, u)));
        }
    }
    while let Some(Reverse((d, v))) = h.pop() {
        if dp[v] < d {
            continue;
        }
        for &(u, c) in graph[v].iter() {
            let d = c + d;
            if dp[u].chmin(d) {
                h.push(Reverse((d, u)));
            }
        }
    }
    if dp[src] != std::u64::MAX {
        println!("{}", dp[src]);
    } else {
        println!("-1");
    }
}

fn main() {
    run();
}


Measured memory_bytes: 2324