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 <stdio.h>
#include <stdlib.h>

#define HASH 200003

int hash_string(char* s)
{
	int i, x = 0;
	for (i = 0; s[i] != 0; i++) x = ((x << 5) + s[i] - 'a') % HASH;
	return x;
}

int lex_smaller(char* s1, char* s2)
{
	int i;
	for (i = 0; s1[i] != 0 && s2[i] != 0; i++) {
		if (s1[i] < s2[i]) return 1;
		else if (s1[i] > s2[i]) return -1;
	}
	if (s1[i] == s2[i]) return 0;
	else if (s1[i] == 0) return 1;
	else return -1;
}

typedef struct List {
	struct List *next;
	int id, len;
	char s[21];
} list;

typedef struct {
	long long key;
	int id;
} data;
 
typedef struct {
	data obj[5000000];
	int size;
} min_heap;
 
void push(data x, min_heap* h)
{
	int i = ++(h->size), j = i >> 1;
	data tmp;
	h->obj[i] = x;
	while (j > 0) {
		if (h->obj[i].key < h->obj[j].key) {
			tmp = h->obj[j];
			h->obj[j] = h->obj[i];
			h->obj[i] = tmp;
			i = j;
			j >>= 1;
		} else break;
	}
}

data pop(min_heap* h)
{
	int i = 1, j = 2;
	data output = h->obj[1], tmp;
	h->obj[1] = h->obj[(h->size)--];
	while (j <= h->size) {
		if (j < h->size && h->obj[j^1].key < h->obj[j].key) j ^= 1;
		if (h->obj[j].key < h->obj[i].key) {
			tmp = h->obj[j];
			h->obj[j] = h->obj[i];
			h->obj[i] = tmp;
			i = j;
			j <<= 1;
		} else break;
	}
	return output;
}

int main()
{
	int i, N, C[51], l[51];
	char S[51][21];
	scanf("%d", &N);
	for (i = 1; i <= N; i++) {
		scanf("%s %d", S[i], &(C[i]));
		for (l[i] = 0; S[i][l[i]] != 0; l[i]++);
	}
	
	int h, j, k, id;
	list *p, *hash[HASH] = {}, appear[2500000];
	data d;
	min_heap heap;
	heap.size = 0;
	for (i = 1, k = 1; i <= N; i++) {
		h = hash_string(S[i]);
		for (p = hash[h]; p != NULL; p = p->next) if (lex_smaller(p->s, S[i]) == 0) break;
		if (p != NULL) {
			d.key = C[i];
			d.id = p->id;
			push(d, &heap);
			d.id *= -1;
			push(d, &heap);
		} else {
			d.key = C[i];
			d.id = k;
			push(d, &heap);
			d.id *= -1;
			push(d, &heap);
			for (j = 0; j < l[i]; j++) appear[k].s[j] = S[i][j];
			appear[k].s[j] = 0;
			appear[k].len = j;
			appear[k].id = k;
			appear[k].next = hash[h];
			hash[h] = &(appear[k++]);
		}
	}
	
	char fla[5000001] = {}, *flag = &(fla[2500000]);
	long long ans = -1, dist;
	while (heap.size > 0) {
		d = pop(&heap);
		if (flag[d.id] != 0) continue;
		else if (d.id == 0 || appear[abs(d.id)].len == 1) {
			ans = d.key;
			break;
		} else flag[d.id] = 1;
		
		id = d.id;
		dist = d.key;
		if (id > 0) {
			for (i = 1; i <= N; i++) {
				for (j = 0; j < appear[id].len && j < l[i] && appear[id].s[j] == S[i][l[i]-j-1]; j++);
				if (j < appear[id].len && j < l[i]) continue;
				else if (j == appear[id].len && j == l[i]) {
					d.key = dist + C[i];
					d.id = 0;
					push(d, &heap);
				} else if (j == l[i]) {
					for (h = 0; appear[id].s[j] != 0; h++, j++) appear[k].s[h] = appear[id].s[j];
					appear[k].s[h] = 0;
					appear[k].len = h;
					h = hash_string(appear[k].s);
					for (p = hash[h]; p != NULL; p = p->next) if (lex_smaller(appear[k].s, p->s) == 0) break;
					if (p != NULL) {
						if (flag[p->id] == 0) {
							d.key = dist + C[i];
							d.id = p->id;
							push(d, &heap);
						}
					} else {
						d.key = dist + C[i];
						d.id = k;
						push(d, &heap);
						appear[k].id = k;
						appear[k].next = hash[h];
						hash[h] = &(appear[k++]);
					}
				} else {
					for (h = 0, j = l[i] - j; h < j; h++) appear[k].s[h] = S[i][h];
					appear[k].s[h] = 0;
					appear[k].len = h;
					h = hash_string(appear[k].s);
					for (p = hash[h]; p != NULL; p = p->next) if (lex_smaller(appear[k].s, p->s) == 0) break;
					if (p != NULL) {
						if (flag[-(p->id)] == 0) {
							d.key = dist + C[i];
							d.id = -(p->id);
							push(d, &heap);
						}
					} else {
						d.key = dist + C[i];
						d.id = -k;
						push(d, &heap);
						appear[k].id = k;
						appear[k].next = hash[h];
						hash[h] = &(appear[k++]);
					}
				}
			}
		} else {
			id *= -1;
			for (i = 1; i <= N; i++) {
				for (j = 0; j < l[i] && j < appear[id].len && S[i][j] == appear[id].s[appear[id].len - j - 1]; j++);
				if (j < appear[id].len && j < l[i]) continue;
				else if (j == appear[id].len && j == l[i]) {
					d.key = dist + C[i];
					d.id = 0;
					push(d, &heap);
				} else if (j == appear[id].len) {
					for (h = 0; S[i][j] != 0; h++, j++) appear[k].s[h] = S[i][j];
					appear[k].s[h] = 0;
					appear[k].len = h;
					h = hash_string(appear[k].s);
					for (p = hash[h]; p != NULL; p = p->next) if (lex_smaller(appear[k].s, p->s) == 0) break;
					if (p != NULL) {
						if (flag[p->id] == 0) {
							d.key = dist + C[i];
							d.id = p->id;
							push(d, &heap);
						}
					} else {
						d.key = dist + C[i];
						d.id = k;
						push(d, &heap);
						appear[k].id = k;
						appear[k].next = hash[h];
						hash[h] = &(appear[k++]);
					}
				} else {
					for (h = 0, j = appear[id].len - j; h < j; h++) appear[k].s[h] = appear[id].s[h];
					appear[k].s[h] = 0;
					appear[k].len = h;
					h = hash_string(appear[k].s);
					for (p = hash[h]; p != NULL; p = p->next) if (lex_smaller(appear[k].s, p->s) == 0) break;
					if (p != NULL) {
						if (flag[-(p->id)] == 0) {
							d.key = dist + C[i];
							d.id = -(p->id);
							push(d, &heap);
						}
					} else {
						d.key = dist + C[i];
						d.id = -k;
						push(d, &heap);
						appear[k].id = k;
						appear[k].next = hash[h];
						hash[h] = &(appear[k++]);
					}
				}
			}
		}
	}
	printf("%lld\n", ans);
	fflush(stdout);
	return 0;
}