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: Accepted)

#include <iostream>
#include <vector>
#include <string>
#include <cstring>

using namespace std;

int valid[2000][10001];
int Z[20000];

void makeValid(const vector<string>& vs, int K){
	memset(valid, 0, sizeof(valid));
	int N = vs.size();
	valid[N-1][K] = 1;
	for(int i=N-2;i>=0;i--){
		for(int j=0;j<=K;j++){
			int p = j + vs[i+1].size();
			valid[i][j] = (valid[i+1][j] || (p <= K && valid[i+1][p]));
		}
	}
}

void makeZ(const string& S){
	Z[0] = S.size();
	int j=0, k=1;
	for(int i=1;i<S.size();i+=k,j=max(0,j-k)){
		while(i+j < S.size() && S[j] == S[i+j]) ++j;
		Z[i] = j;
		for(k=1;i+k < S.size() && k+Z[k] < j;k++) Z[i+k] = Z[k];
	}
	Z[S.size()] = 0;
}

int main(){
	int N, K;
	int use[2][10001];
	while(cin >> N >> K){
		vector<string> S(N);
		for(int i=0;i<N;i++) cin >> S[i];
		makeValid(S, K);
		memset(use, 0, sizeof(use));
		use[0][0] = 1;
		string best = "";
		for(int i=0;i<N;i++){
			int cur = i%2, next = 1-cur;
			memset(use[next], 0, sizeof(use[next]));
			makeZ(S[i] + best);
			int joinPos = -1;
			for(int j=best.size();j>=0;j--){
				if(!use[cur][j]) continue;
				if(j+S[i].size() > K || !valid[i][j+S[i].size()]) continue;
				if(joinPos == -1){
					int z = Z[S[i].size() + j];
					if(z+j >= best.size() || (z < S[i].size() && S[i][z] < best[z+j])){
						joinPos = j;
					}
				} else {
					int z = min((int)S[i].size(), Z[S[i].size() + j]);
					if(z+j < joinPos){
						if(z < S[i].size() && S[i][z] < best[z+j]){
							joinPos = j;
						}
					} else {
						int z2 = Z[joinPos - j];
						if(z2+joinPos-j < S[i].size() && S[i][z2+joinPos-j] < S[i][z2]){
							joinPos = j;
						}
					}
				}
			}
			for(int j=0;j<=best.size();j++){
				if(!use[cur][j]) continue;
				if(joinPos == -1 || j <= joinPos + Z[S[i].size()+joinPos]){
					if(valid[i][j]) use[next][j] = 1;
				}
				if(joinPos != -1 && j <= joinPos && j+S[i].size() <= K && valid[i][j+S[i].size()]){
					int z = min((int)S[i].size(), Z[S[i].size() + j]);
					if(z == S[i].size() && j+S[i].size() <= joinPos){
						use[next][j+S[i].size()] = 1;
					} else if(j+z >= joinPos){
						int z2 = Z[joinPos - j];
						if(joinPos + z2 >= j+S[i].size()) use[next][j+S[i].size()] = 1;
					}
				}
			}
			if(joinPos != -1) best = best.substr(0, joinPos) + S[i];
		}
		cout << best << endl;
	}
}