Problem:
Problem J: Billion Million Thousand

A linguist, Nodvic Natharus Damenhof (commonly called Dr. Usoperant), invented an artificial language Usoperant in 2007. The word usoperant means ‘one which tires’. Damenhof’s goal was to create a complex and
pedantic language that would remind many difficulties in universal communications. Talking in Usoperant, you
should remember the importance of choosing your words in many conversations.

For example of the complexity, you may be confused by the way to say large numbers. Usoperant has some
words that indicate exponential numbers in decimal, described as 10p where p is a positive integer. In terms of
English, those words might include thousand for 103 (1,000), million for 106 (1,000,000), and undecillion for
1036 (1,000,000,000,000,000,000,000,000,000,000,000,000).

You can concatinate those words to express larger numbers. When two words w1 and w2 mean numbers 10p1
and 10p2 respectively, a concatinated word w1w2 means 10p1+p2. Using the above examples in English (actually
the following examples are incorrect in English), you can say 109 by millionthousand, 1012 by millionmillion
and 1039 by undecillionthousand. Note that there can be multiple different expressions for a certain number.
For example, 109 can also be expressed by thousandthousandthousand. It is also possible to insert separators
between the adjacent components like million-thousand and thousand-thousand-thousand.

In this problem, you are given a few of such words, their representing digits and an expression of a certain number
in Usoperant. Your task is to write a program to calculate the length of the shortest expression which represents
the same number as the given expression.

The expressions in the input do not contain any separators like millionthousand. In case of ambiguity, the
expressions should be interpreted as the largest number among possibles. The resultant expressions should
always contain separators like million-thousand, so we can distinguish, for example, x-x (a concatinated word of
two x's) and xx (just a single word). The separators should not be counted in the length.

Input

The input consists of multiple test cases. Each test case begins with a line including an integer N (1 ≤ N ≤ 100).
The integer N indicates the number of words in the dictionary of exponential numbers.

The following N lines give the words in the dictionary. Each line contains a word wi and an integer pi (1 ≤ i ≤ N,
1 ≤ pi ≤ 10), specifying that the word wi expresses an exponential number 10pi in Usoperant. Each wi consists
of at most 100 alphabetical letters.

Then a line which contains an expression of a number in Usoperant follows. The expression consists of at most
200 alphabetical letters.

The end of the input is indicated by a line which contains only a single 0.

Output

For each test case, print a line which contains the case number and the length of the shortest expression which
represents the same number as the given expression in the input.

Sample Input

3
billion 9
million 6
thousand 3
billionmillionthousand
3
oku 8
sen 3
man 4
okusenman
2
nico 2
video 4
niconicovideo
6
abcd 1
efgh 2
abcde 4
fgh 6
y 8
yy 10
abcdefgh
0

Output for the Sample Input

Case 1: 14
Case 2: 9
Case 3: 10
Case 4: 2

Note:

In the fourth case, the word abcdefgh can be separated as abcd-efgh (representing 103 ) and abcde-fgh
(representing 1010 ), and by the rule described in the problem statement, this word should be interpreted as 1010.
As this number can be expressed by yy, the length of the shortest expression is two (as in the sample output). The
existence of y-y (representing 1016 ) is not a problem here, because we can distinguish yy and y-y as long as we
always use separators.

Solution in C++14 (judge verdict: Accepted)

#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;



 int mod = 1000000007;
struct Mod {
public:
	int num;
	Mod() : Mod(0) { ; }
	Mod(long long int n) : num((n % mod + mod) % mod) {
		}
	Mod(int n) : Mod(static_cast<long long int>(n)) { ; }
	operator int() { return num; }
};

Mod operator+(const Mod a, const Mod b) { return Mod((a.num + b.num) % mod); }
Mod operator+(const long long int a, const Mod b) { return Mod(a) + b; }
Mod operator+(const Mod a, const long long int  b) { return b + a; }
Mod operator++(Mod &a) { return a + Mod(1); }
Mod operator-(const Mod a, const Mod b) { return Mod((mod + a.num - b.num) % mod); }
Mod operator-(const long long int a, const Mod b) { return Mod(a) - b; }
Mod operator--(Mod &a) { return a - Mod(1); }
Mod operator*(const Mod a, const Mod b) { return Mod(((long long)a.num * b.num) % mod); }
Mod operator*(const long long int a, const Mod b) { return Mod(a)*b; }
Mod operator*(const Mod a, const long long int b) { return Mod(b)*a; }
Mod operator*(const Mod a, const int b) { return Mod(b)*a; }
Mod operator+=(Mod &a, const Mod b) { return a = a + b; }
Mod operator+=(long long int &a, const Mod b) { return a = a + b; }
Mod operator-=(Mod &a, const Mod b) { return a = a - b; }
Mod operator-=(long long int &a, const Mod b) { return a = a - b; }
Mod operator*=(Mod &a, const Mod b) { return a = a * b; }
Mod operator*=(long long int &a, const Mod b) { return a = a * b; }
Mod operator*=(Mod& a, const long long int &b) { return a = a * b; }
Mod operator^(const Mod a, const int n) {
	if (n == 0) return Mod(1);
	Mod res = (a * a) ^ (n / 2);
	if (n % 2) res = res * a;
	return res;
}
Mod mod_pow(const Mod a, const long long  int n) {
	if (n == 0) return Mod(1);
	Mod res = mod_pow((a * a), (n / 2));
	if (n % 2) res = res * a;
	return res;
}
Mod inv(const Mod a) { return a ^ (mod - 2); }
Mod operator/(const Mod a, const Mod b) {
	assert(b.num != 0);
	return a * inv(b);
}
Mod operator/(const long long int a, const Mod b) {
	return Mod(a) / b;
}
Mod operator/=(Mod &a, const Mod b) {
	return a = a / b;
}

#define MAX_MOD_N 1024000

Mod fact[MAX_MOD_N], factinv[MAX_MOD_N];
void init(const int amax = MAX_MOD_N) {
	fact[0] = Mod(1); factinv[0] = 1;
	for (int i = 0; i < amax - 1; ++i) {
		fact[i + 1] = fact[i] * Mod(i + 1);
		factinv[i + 1] = factinv[i] / Mod(i + 1);
	}
}
Mod comb(const int a, const int b) {
	return fact[a] * factinv[b] * factinv[a - b];
}

vector<pair<int, int>>get_connect(int N, int x, int y) {
	vector<pair<int,int>>anss;
	{
		int ax=x-1;
		int ay=y;
		anss.emplace_back(ax,ay);
	}
	{
		int ax=x+1;
		int ay=y;
		anss.emplace_back(ax, ay);

	}

	//lu
	{
		int ax,ay;
		if (y < N) {
			ax=x-1;
			ay=y-1;
		}
		else {
			ax=x;
			ay=y-1;
		}
		anss.emplace_back(ax, ay);

	}

	//ru
	{
		int ax,ay;
		if (y < N) {
			ax=x;
			ay=y-1;
		}
		else {
			ax=x+1;
			ay=y-1;
		}
		anss.emplace_back(ax, ay);

	}

	//ld
	{
		int ax,ay;
		if (y < N - 1) {
			ax=x;
			ay=y+1;
		}
		else {
			ax=x-1;
			ay=y+1;
		}
		anss.emplace_back(ax, ay);

	}
	//rd
	{
		int ax,ay;
		if (y < N - 1) {
			ax=x+1;
			ay=y+1;
		}
		else {
			ax=x;
			ay=y+1;
		}
		anss.emplace_back(ax, ay);

	}
	vector<pair<int,int>>real_anss;
	for (auto ans : anss) {
		int ax(ans.first);
		int ay(ans.second);
		bool ok=true;
		if(ay<0||ay>=2*N-1)ok=false;
		if (ay < N) {
			if(ax<0||ax>=N+ay)ok=false;
		}
		else {
			if (ax < 0 || ax>=3*N-ay-2)ok=false;
		}
		if(ok)real_anss.emplace_back(ans);
	}
	return real_anss;
}


template<typename T>
vector<vector<T>> keisann(const vector<vector<T>>l, const vector<vector<T>>r) {
	vector<vector<T>>ans(l.size(), vector<T>(r[0].size()));
	assert(l[0].size() == r.size());
	for (unsigned int h = 0; h < l.size(); ++h) {
		for (unsigned int i = 0; i < r.size(); ++i) {
			for (unsigned int w = 0; w < r[0].size(); ++w) {

				ans[h][w] += l[h][i] * r[i][w];
			}
		}
	}
	return ans;
}

template<typename T>
vector<vector<T>>powgyou(vector<vector<T>>a, const long long int n) {
	assert(a.size() == a[0].size());
	if (!n) {
		vector<vector<T>>e(a.size(), vector<T>(a[0].size()));
		for (unsigned int i = 0; i < a.size(); ++i) {
			e[i][i] = 1;
		}
		return e;
	}
	if (n == 1)return a;
	else {
		vector<vector<T>>ans(a.size(), vector<T>(a[0].size(), 0));
		ans = powgyou(a, n / 2);
		ans = keisann(ans, ans);
		if (n % 2) {
			ans = keisann(ans, a);
		}
		return ans;
	}
}


int main() {
	int case_id=0;
	while (true) {
		case_id++;
		int N;cin>>N;
		if(!N)break;
		map<string,int>mp;
		for (int i = 0; i < N; ++i) {
			string st;cin>>st;
			int n;cin>>n;
			mp[st]=n;
		}


		int need_num = -1;
		{
			string st; cin >> st;
			vector<int>nums(st.size() + 1, -100000);
			nums[0] = 0;
			for (int i = 0; i < st.size(); ++i) {
				for (auto m : mp) {
					if (st.substr(i, m.first.size()) == m.first) {
						nums[i + m.first.size()] = max(nums[i + m.first.size()], nums[i] + m.second);
					}
				}
			}
			need_num=nums[st.size()];
		}
		vector<int>dp(need_num+10000,100000);
		dp[0]=0;
		for (int i = 0; i < need_num; ++i) {
			for (auto m : mp) {
				dp[i+m.second]=min(dp[i+m.second],int(dp[i]+m.first.size()));
			}
		}
		cout<<"Case "<<case_id<<": "<<dp[need_num]<<endl;
	}
	
	return 0;
}