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 <bitset>
#include <cstdio>
#include <cstring>
#include <functional>
#include <utility>
#include <string>

const int N = 2001;
const int M = 20001;

using Bitset = std::bitset<M>;
using Segment = std::pair<int, bool>;

int n, m, z[M];
bool has[M];
std::string s[N];
Bitset can[N];

int main()
{
#ifdef LOCAL_JUDGE
    freopen("D.in", "r", stdin);
#endif
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++ i) {
        static char buf[M];
        scanf("%s", buf);
        s[i] = buf;
    }
    can[n].set(0);
    for (int i = n; i >= 1; -- i) {
        can[i - 1] = can[i] | can[i] << s[i - 1].size();
    }
    has[0] = true;
    std::string candidate;
    for (int i = 0; i < n; ++ i) {
//printf("Stage %d: \n", i);
        std::string buf = s[i] + "$" + candidate;
        memset(z, 0, sizeof(z));
        for (int i = 1, j = 0; i < (int)buf.size(); ++ i) {
            if (i < j + z[j]) {
                z[i] = std::min(z[i - j], j + z[j] - i);
            }
            while (i + z[i] < (int)buf.size() && buf[z[i]] == buf[i + z[i]]) {
                z[i] ++;
            }
            if (j + z[j] < i + z[i]) {
                j = i;
            }
        }
//puts(buf.c_str());
//for (int j = 0; j < (int)buf.size(); ++ j) { printf("%d", z[j]); } puts("");
        int l = z[0] = s[i].size();
        Segment best {-1, false};

        auto get_len = [&](const Segment& u)
        {
            return u.first + (u.second ? l : 0);
        };

        auto at = [&](const Segment& a, int pos) -> char
        {
            return pos < a.first ? candidate[pos] : s[i][pos - a.first];
        };

        std::function<int(const Segment&, const Segment&)> compare = [&](const Segment& a, const Segment& b)
        {
            if (a.first < b.first) {
                return -compare(b, a);
            }
            // a.first >= b.first
            int lcp = b.first;
            if (b.second) {
                lcp += z[l + 1 + b.first];
                if (a.second && lcp == a.first) {
                    lcp += z[a.first - b.first];
                }
            }
            if (lcp == std::min(get_len(a), get_len(b))) {
                return 0;
            }
            return at(a, lcp) - at(b, lcp);
        };

        auto update = [&](int pre_len, bool has_suf)
        {
            if (best.first == -1) {
                best = {pre_len, has_suf};
                return true;
            }
            int ret = compare(best, {pre_len, has_suf}); // a - b
            if (ret > 0) {
                best = {pre_len, has_suf};
            }
            return ret >= 0;
        };

        for (int j = m; j >= 0; -- j) {
            bool ok = false;
            if (has[j] && can[i + 1].test(m - j)) {
                ok |= update(j, false);
            }
            if (j >= l && has[j - l] && can[i + 1].test(m - j)) {
                ok |= update(j - l, true);
            }
            has[j] = ok;
        }
        candidate = candidate.substr(0, best.first);
        if (best.second) {
            candidate += s[i];
        }
        for (int j = (int)candidate.size() + 1; j <= m; ++ j) {
            has[j] = false;
        }
    }
    puts(candidate.c_str());
}