Problem:
Score : 1500 points

Problem Statement

Iroha has a sequence of N strings s_1, s_2, ..., s_N.

She will choose some (possibly all) strings from the sequence, then concatenate those strings retaining the relative order, to produce a long string.

Among all strings of length K that she can produce in this way, find the lexicographically smallest one.

Constraints

1 ≦ N ≦ 2000

1 ≦ K ≦ 10^4

For each i, 1 ≦ |s_i| ≦ K.

|s_1| + |s_2| + ... + |s_N| ≦ 10^6

For each i, s_i consists of lowercase letters.

There exists at least one string of length K that Iroha can produce.

Input

The input is given from Standard Input in the following format:

N K
s_1
s_2
:
s_N

Output

Print the lexicographically smallest string of length K that Iroha can produce.

Sample Input 1

3 7
at
coder
codar

Sample Output 1

atcodar

at and codar should be chosen.

Sample Input 2

3 7
coder
codar
at

Sample Output 2

codarat

codar and at should be chosen.

Sample Input 3

4 13
kyuri
namida
zzzzzzz
aaaaaa

Sample Output 3

namidazzzzzzz

namida and zzzzzzz should be chosen.

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include<string>
#include<vector>
std::vector<int> z_algorithm(const std::string& S) {
  std::vector<int> Z(S.size(), S.size());
  for(int i = 1, L = 0, R = 0; i < S.size(); ++i) {
    if(i > R) {
      L = R = i;
      while(R < S.size() && S[R - L] == S[R]) ++R;
      Z[i] = R-- - L;
    } else {
      if(Z[i - L] < R - i + 1) Z[i] = Z[i - L];
      else {
        L = i;
        while(R < S.size() && S[R - L] == S[R]) ++R;
        Z[i] = R-- - L;
      }
    }
  }
  return Z;
}

#include<bits/stdc++.h>
using namespace std;

int cmp(const auto& S, const auto& CS, const auto& Z, int best, int j) {
  if(CS.empty()) return 1;
  if(best == -1) {
    // CS <=> CS[0...j] + S
    if(CS.size() <= j) return 0;      // CS ⊂ CS[0...j] + S
    auto z = Z[S.size() + j];
    if(z >= S.size()) return 0;       // CS ⊇ CS[0...j] + S
    if(j + z >= CS.size()) return 0;  // CS ⊆ CS[0...j] + S
    if(CS[j + z] > S[z]) return 1;
    return -1;
  } else {
    // CS[0...best] + S <=> CS[0...j] + S
    if(best > j) return -cmp(S, CS, Z, j, best);
    if(best == j) return 0;                     // CS[0...best] + S = CS[0...j] + S
    // CS[0...best] + S <=> CS[0...j-1]
    auto z = Z[S.size() + best];
    if(best + z < j) {
      if(S[z] > CS[best + z]) return 1;
      return -1;
    }
    // S[d...] <=> S
    auto d = j - best;
    z = Z[d];
    if(d + z >= S.size()) return 0;             // CS[0...best] + S ⊂ CS[0...j] + S
    if(S[d + z] > S[z]) return 1;
    return -1;
  }
}

int main() {
  int N, K;
  cin >> N >> K;
  vector<string> S(N);
  for(auto& i: S) cin >> i;

  vector<vector<bool>> reach(N + 1, vector<bool>(K + 1));
  reach[N][0] = true;
  for(int i = N - 1; 0 <= i; --i) {
    reach[i] = reach[i + 1];
    for(int j = K; S[i].size() <= j; --j) reach[i][j] = reach[i][j] | reach[i][j - S[i].size()];
  }

  vector<string> CS(N + 1);
  vector<vector<bool>> dp(N + 1, vector<bool>(K + 1));
  dp[0][0] = true;
  for(int i = 0; i < N; ++i) {
//     cout<<"CS: "<<CS[i]<<endl;
//     cout<<"dp:";for(auto k:dp[i])cout<<" "<<k;cout<<endl;
//     cout<<"nx:";for(auto k:reach[i+1])cout<<" "<<k;cout<<endl;
    auto Z = z_algorithm(S[i] + CS[i]);
    int best = -1;
    CS[i + 1] = CS[i];
    for(int j = 0; j <= K - S[i].size(); ++j) {
      if(!dp[i][j]) continue;
      if(!reach[i + 1][K - j - S[i].size()]) continue;
      auto c = cmp(S[i], CS[i], Z, best, j);
      if(c < 0) continue;
      if(c == 0 && j + S[i].size() <= CS[i + 1].size()) continue;
      best = j;
      CS[i + 1] = CS[i].substr(0, best) + S[i];
    }
//     cout<<best<<endl;
    int dif = 0;
    while(dif < CS[i].size() && dif < CS[i + 1].size() && CS[i][dif] == CS[i + 1][dif]) ++dif;
    if(dif == min(int(CS[i].size()), int(CS[i + 1].size()))) dif = K + 1;
    for(int j = 0; j <= K; ++j) {
      if(!dp[i][j]) continue;
      if(best == -1) {
        if(reach[i + 1][K - j]) dp[i + 1][j] = true;
      } else {
        if(j < dif) if(reach[i + 1][K - j]) dp[i + 1][j] = true;
        if(K < j + S[i].size()) continue;
        if(!reach[i + 1][K - j - S[i].size()]) continue;
        if(cmp(S[i], CS[i], Z, best, j) < 0) continue;
        dp[i + 1][j + S[i].size()] = true;
      }
    }
  }

  cout << CS[N] << endl;
}