Problem:
Kth Sentence

A student, Kita_masa, is taking an English examination.
In this examination, he has to write a sentence of length m.

Since he completely forgot the English grammar, he decided to consider all sentences of length m constructed by concatenating the words he knows and write the K-th sentence among the candidates sorted in lexicographic order.
He believes that it must be the correct sentence because K is today's lucky number for him.

Each word may be used multiple times (or it's also fine not to use it at all) and the sentence does not contain any extra character between words.
Two sentences are considered different if the order of the words are different even if the concatenation resulted in the same string.

Input

The first line contains three integers n (1 \leq n \leq 100), m (1 \leq m \leq 2000) and K (1 \leq K \leq 10^{18}), separated by a single space.
Each of the following n lines contains a word that Kita_masa knows.
The length of each word is between 1 and 200, inclusive, and the words contain only lowercase letters.
You may assume all the words given are distinct.

Output

Print the K-th (1-based) sentence of length m in lexicographic order.
If there is no such a sentence, print "-".

Sample Input 1

2 10 2
hello
world

Output for the Sample Input 1

helloworld

Sample Input 2

3 3 6
a
aa
b

Output for the Sample Input 2

aba

Sample Input 3

2 59 1000000000000000000
a
b

Output for the Sample Input 3

-

Solution in C++14 (judge verdict: Memory Limit Exceeded)

#include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,NAME,...) NAME
#define pr(...) cerr<< GET_MACRO(__VA_ARGS__,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
using namespace std;
using Int = long long;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<60); // ~ 10^18
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
using T = tuple<Int,Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
ostream& operator<<(ostream& o,P p){return o<<"("<<p.first<<","<<p.second<<")";}
ostream& operator<<(ostream& o,T t){return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
istream& operator>>(istream& i,P &p){return i>>p.first>>p.second;}
ostream& operator<<(ostream& o,vector<auto> &a){Int i=0;for(auto t:a)o<<(i++?" ":"")<<t;return o;}
istream& operator>>(istream& i,vector<auto> &a){for(auto &t:a)i>>t;return i;}
void prArr(auto a,string s=" "){Int i=0;for(auto t:a)cout<<(i++?s:"")<<t;cout<<endl;}

template <Int X/*文字の種類*/>
class Trie{
public:
  struct Node{
    char c;         //今の文字
    int pre;        //前の頂点番号
    short val;        //
    bool exist;      //単語が存在するか
    vector<int> to; //次の頂点番号
    Node(){};
    Node(char c,Int pre,Int val=0,Int exist=0):c(c),pre(pre),val(val),exist(exist),to(X,-1){};
  };
   
  vector<Node> v;
  function<Int(char)> toI; //文字から数字に変換する関数
   
  Trie(function<Int(char)> toI=[](char ch){return ch-'A';} ,char c = '$')
    :toI(toI){v.reserve(20000);v.push_back(Node(c,-1,0/*!!!!!*/));};
 
  Int size(){return v.size();}
  void Assert(Int pos){assert(0 <= pos && pos<(Int)v.size());}
  Int go(Int pos,char c){Assert(pos);return v[pos].to[toI(c)];}
  Int go(const string &s,Int pos = 0){
    for(char c:s){
      pos = go(pos,c);
      if(pos == -1) return -1;
    }
    return pos;
  }
  Int back(Int pos){Assert(pos);return v[pos].pre;}
  Int getVal(Int pos){Assert(pos);return v[pos].val;} //0だったら単語が存在しない。
  Int exist(Int pos){Assert(pos);return v[pos].exist;}
   
  void add(const string &s,Int val = 1){
    Int pos = 0;
    for(char c:s){
      if(go(pos,c) != -1){pos = go(pos,c);continue;}
      v.push_back(Node(c,pos));
      pos = v[pos].to[toI(c)] = v.size()-1;
    }
    v[pos].exist = 1;
    //v[pos].val = max(v[pos].val, val);  //min,max,+ 臨機応変に変えて
  }
};
 
Int m;
Trie <26> trie([](char ch){return ch - 'a';});

map<signed, Int> mem;
Int dfs(int pos,int len){
  signed hs = pos * 20010 + len;
  if(pos == -1) return 0;
  if(len == m) return trie.exist(pos);
  if(mem.count(hs)) return mem[hs];
  
  Int res = 0;
  {
    for(char ch = 'a'; ch <= 'z'; ch++){
      Int a =  dfs(trie.go(pos, ch), len+1);
      Int b =  trie.exist(pos)? dfs(trie.go(0, ch), len+1):0;
      res = min(INF, res + a + b);
      if(res == INF) break;
    }
  }
  return mem[hs] = res;
}

bool overflow(ll a,ll b){return a!=0 && b!= 0 && a > LONG_MAX/b;}

Int mult(Int a,Int b){
  if(overflow(a, b) || overflow(b, a)) return INF;
  return min(INF, a * b);
}
 
string ans;
void restore(map<Int,Int> &Pos,Int len,Int K){
  if(len == m) return;
  auto erase=[&](int to){
    if(to == -1) return;
    mem.erase(to*20010+len+1);
  };
  
  char to = -1;
  Int sum = 0;
  {
    for(char ch = 'a'; ch <= 'z'; ch++){
      Int s = 0;
      for(const auto t:Pos){
	Int pos = t.first;
	Int val = t.second;
	Int a = mult(val , dfs(trie.go(pos, ch), len+1));
	Int b = trie.exist(pos)?  mult(val , dfs(trie.go(0, ch), len+1)):0;
	s = min(INF, s + min(INF,a + b));
	erase(trie.go(pos, ch));

      }
      if(sum + s >= K) {to = ch; break;}
      sum += s;
       
    }
  }
 
  if(to == -1){ans = "-";return;}
   
  {
    ans += to;
    map<Int,Int> To;
    for(auto t:Pos){
      Int pos = t.first;
      Int val = t.second;
      if(dfs(trie.go(pos, to), len+1)) To[trie.go(pos, to)] += val;
      if(trie.exist(pos) && dfs(trie.go(0,to), len+1)) To[trie.go(0,to)] += val;
    }
    Pos.clear();
    restore(To, len+1, K - sum);
  }
}
 
signed main(){
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);
  Int n, K;
  cin>>n>>m>>K;
 
  for(Int i=0;i<n;i++){
    string s;
    cin>>s;
    trie.add(s);
  }
  
  //pr(trie.size(), dfs(0,0));
  map<Int,Int> Pos; Pos[0] = 1;
  restore(Pos, 0, K);
  cout<<ans<<endl;
  return 0;
}