Problem p03353 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;

using LL = long long;
using ULL = unsigned long long;
constexpr int INF = 2147483647;
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};

// 以下はC++の練習のための便利プログラム　あんまり便利じゃないけど…
//------------------------------------------便利型----------------------------------------------
// 二次元の点
// TODO map,setのほうが楽かも
template <typename T> struct Point2D {
  T x;
  T y;

  friend ostream &operator<<(ostream &os, const Point2D<T> &point);

  bool operator<(const Point2D &right) const {
    return (this->x == right.x) ? (this->y > right.y) : (this->x > right.x);
  }
};

ostream &operator<<(ostream &os, const Point2D<int> &point) {
  os << "(" << point.x << ',' << point.y << ")";
  return os;
}

// 長くて読みづらかったのでエイリアステンプレートに
template <class T> using StdAlloc = std::allocator<T>;

// 簡単な２次元配列
// Tにboolを使うとおかしくなるので、bitset<1>を使うこと
template <class T> class Array2D {
public:
  struct Array2DAccessor {
    LL h;
    LL w;

    Array2DAccessor operator+(const Array2DAccessor &right) const {
      return {h + right.h, w + right.w};
    }

    const static initializer_list<Array2DAccessor> UpDownLeftRight;
  };

public:
  Array2D(size_t height, size_t width, T init) {
    data = vector<vector<T>>(height, vector<T>(width, init));
  }

  // ループ　インデックスなし
  void ForEach(function<void(T &)> func) {
    for (auto &row : data) {
      for (T &column : row) {
        func(column);
      }
    }
  }

  // template<class FUNC>
  // void ForEach(FUNC func)
  //{
  //	for (auto& row : data) {
  //		for (T& column : row) {
  //			func(column);
  //		}
  //	}
  // }

  ////ループ　インデックスあり、return条件あり
  ////作ってみたけどめっちゃ使いにくい…
  // void ForEach(	//function<void(ULL, ULL, T&)> func,
  //				function<bool()> IsReturnAndClosureW = []() {return false;
  //}, 				function<bool()> IsReturnAndClosureH = []() {return false; }
  //			)
  //{
  //	for (ULL h = 0ULL; h < data.size(); h++) {
  //		if (IsReturnAndClosureW(h, w, data[h][w])) {
  //			continue;
  //		}
  //		for (ULL w = 0ULL; w < data[h].size(); w++) {
  //			if (IsReturnAndClosureH(h, w, data[h][w])) {
  //				break;
  //			}
  //			//func(h, w, data[h][w]);
  //		}
  //	}
  // }

  ULL GetHeight() { return data.size(); }

  ULL GetWidth() { return data.front().size(); }

  template <class INDEX> vector<T> &operator[](INDEX indx) {
    return data[indx];
  }

  bool IsValid(const Array2DAccessor &indx) const {
    return 0LL <= indx.h && indx.h < (unsigned)data.size() && 0LL <= indx.w &&
           indx.w < (unsigned)data.front().size();
  }

public:
  vector<vector<T>> data;
};

template <class T>
const initializer_list<typename Array2D<T>::Array2DAccessor>
    Array2D<T>::Array2DAccessor::UpDownLeftRight = {
        {0LL, 1LL}, {0LL, -1LL}, {-1LL, 0LL}, {1LL, 0LL}};

//------------------------------------------便利型----------------------------------------------

// 深さ優先探索
// 再帰で実装するとStack Overflowになる…　Atcoderのスタックサイズはいくつ？
template <class Container, class Accessor>
tuple<ULL> DepthFirstSearch(
    Container &field, const Accessor &start,
    const initializer_list<Accessor> &searchDir,
    const function<void(const Accessor &, Container &)> &Work,
    const function<bool(const Accessor &, Container &)> &IsSearch) {
  tuple<ULL> info = make_tuple(0); // 探索の情報　てきとー
  queue<Accessor> taskQueue;
  taskQueue.push(start);

  while (!taskQueue.empty()) {
    const auto task = taskQueue.front();
    taskQueue.pop();

    // 各方向へ探索
    for (const auto &df : searchDir) {
      auto indx = task + df;
      if (!IsSearch(indx, field)) {
        continue;
      }

      Work(indx, field);

      // 探索に関する各種情報を更新
      get<0>(info)++;
      taskQueue.push(indx);
    }
  }

  return info;
}

//-----------------------------------------便利関数---------------------------------------------
// デバッグ用乱数
// random_device rnd;
// mt19937 mt(0);
// uniform_int_distribution<int> rand10_9(0, 10);
// for (unsigned i = 0; i < N; i++) {
//	numbers[i] = (long long)(rand10_9(mt) - 10);
//	//numbers[i] = 0;
//}

// コンテナに格納された要素がそれぞれいくつあるか
// 処理時間は遅い
template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void EachElementNum(const Container<T> &container, map<T, LL> &numberCounts) {
  for (const auto &data : container) {
    numberCounts[data] =
        (numberCounts.count(data) == 0) ? 1 : ++numberCounts[data];
  }
}

template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void EachElementNum(const Container<T> &container,
                    vector<tuple<T, LL>> &numberCounts) {
  map<T, LL> eachElementNum;
  EachElementNum(container, eachElementNum);
  for (const auto &info : eachElementNum) {
    numberCounts.emplace_back(make_tuple(info.first, info.second));
  }
}

// 累積和
template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void PrefixSum(Container<T> &c) {
  for (auto now = begin(c) + 1, prev = begin(c); now != end(c); now++, prev++) {
    *now += +*prev;
  }
}

// ユニークな要素数
template <class T> unsigned long long UniqueElementNum(const vector<T> &data) {
  auto copy = data;

  sort(begin(copy), end(copy));
  copy.erase(unique(begin(copy), end(copy)), end(copy));

  return copy.size();

  // set<unsigned long long>(begin(copy), end(copy)).size();
  // //１行版　マクロにしても良い
}

// ある閉区間の範囲内かどうか　やっぱり使いづらい
template <class T> bool IsInClose(T x, T min, T max) {
  return (min <= x && x <= max);
}

// 値が昇順になっているか
template <class T> bool IsInOrder(const T &value1, const T &value2) {
  return !(value2 < value1);
}

template <class T>
bool IsInOrder(const T &value1, const T &value2, const T &value3) {
  return !(value2 < value1) && !(value3 < value2);
}

template <class T>
bool IsInOrder(const T &value1, const T &value2, const T &value3,
               const T &value4) {
  return !(value2 < value1) && !(value3 < value2) && !(value4 < value3);
}

// 値が範囲内かどうか
template <class T>
inline bool IsInRange(const T &min, const T &value, const T &max) {
  return IsInOrder(min, value, max);
}

// 最小公倍数 #TODO template化
long long gcd(long long a, long long b) {
  long long c;

  if (a < b) {
    a += b;
    b = a - b;
    a -= b;
  }

  while (b != 0) {
    c = a % b;
    a = b;
    b = c;
  }

  return a;
}

// 素数かどうか #TODO template化
bool IsPrime(ULL num) {
  if (num < 2)
    return false;
  else if (num == 2)
    return true;
  else if (num % 2 == 0)
    return false; // 偶数はあらかじめ除く

  double sqrtNum = sqrt(num);
  for (ULL i = 3; i <= sqrtNum; i += 2) {
    if (num % i == 0) {
      // 素数ではない
      return false;
    }
  }

  // 素数である
  return true;
}

// 素因数分解　試し割り（sqrt(n)まで）
// もっと早い方法もあるらしい…
void DecomposePrime(ULL n, vector<tuple<ULL, ULL>> &result) {
  vector<ULL> primeList;

  // 割る数の初期値
  ULL a = 2;

  // √n ≧ a ( n ≧ a * a ) の間ループ処理
  while (n >= a * a) {
    // a で割り切れたら、a は素因数
    // そして、割られる数を a で割る
    // a で割り切れなかったら、 a を 1 増加させる
    if (n % a == 0) {
      primeList.emplace_back(a);
      n /= a;
    } else {
      a++;
    }
  }
  // 最後に残った n は素因数
  primeList.emplace_back(n);

  // 素因数がそれぞれいくつあるかを調べる
  set<ULL> uniquePrimeList(begin(primeList), end(primeList));
  for (const auto &p : uniquePrimeList) {
    ULL primeNum = count(begin(primeList), end(primeList), p);
    result.emplace_back(make_tuple(p, primeNum));
  }
}

// n個からr個取り出す組み合わせの数
template <typename Type> Type nCr(Type n, Type r) {
  Type ans = 1;
  for (Type i = n; i > n - r; --i) {
    ans = ans * i;
  }
  for (Type i = 1; i < r + 1; ++i) {
    ans = ans / i;
  }
  return ans;
}

// 新しい方に対応したい場合、以下を参考にする
// コンテナへ要素を追加
// プリミティブ型など
template <class Num, class Container>
void InitContainer(Num num, Container &container) {
  container.resize(num);
  for (auto &d : container) {
    cin >> d;
  }
}

// コンテナへ要素を追加
// Container<Point2D<T>>で特殊化　読みにくい…　マクロにする？
template <class Num,
          template <class T, class Allocator = StdAlloc<T>> class Container,
          class T2>
void InitContainer(Num num, Container<Point2D<T2>> &firstContainer) {
  firstContainer.resize(num);
  for (auto &d : firstContainer) {
    cin >> d.x >> d.y;
  }
}

// コンテナへ要素を追加　を呼び出す処理
template <class Num, class First, class... Rest>
void InitContainer(Num num, First &first, Rest &...rest) {
  InitContainer(num, first);
  InitContainer(num, rest...);
}

// 要素数Nと各要素をコンテナに格納
// コンテナを複数個取れるようにしてみた　テンプレートの練習
template <class Num, class... Container>
void InitNumAndContainer(Num &num, Container &...container) {
  cin >> num;
  InitContainer(num, container...);
}

// コンテナの内容をstreamへ出力
// 今はてきとーにcoutへ改行しながら　果たしてこの書き方は便利なのか…？
// #TODO 引数増やしたりオーバーロード増やしたり
template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void ShowContainer(const Container<T> &container) {
  ostream_iterator<T> outItr(cout, "\n");
  copy(container.begin(), container.end(), outItr);
  cout << endl;
}

//-----------------------------------------便利関数---------------------------------------------

int main() {
  string str;
  ULL K;
  cin >> str >> K;

  auto SearchMinChar = [](const string &str, char minC) {
    char result = minC;
    for (const auto &s : str) {
      result = min(result, s);
    }

    return result;
  };

  auto MakeSubstr = [](const string &str, char minC,
                       vector<string> &resultSubStrList) {
    vector<int> minCIndxList;

    for (auto s = str.rbegin(); s != str.rend(); s++) {
      if (*s != minC) {
        continue;
      }

      int fromEndIndx = distance(str.rbegin(), s);
      minCIndxList.emplace_back((str.size() - 1) - fromEndIndx);
    }

    vector<string> subStrList(minCIndxList.size(), "");
    for (int i = 0; i < 5; i++) { // #TODO 5はてきとう
      for (int j = 0; j < subStrList.size(); j++) {
        int indx = minCIndxList[j];
        if (indx + i >= str.size()) {
          continue;
        }

        subStrList[j] += str[indx + i];
        resultSubStrList.emplace_back(subStrList[j]);
      }
    }
  };

  char minC = SearchMinChar(str, 'z');
  vector<string> resultSubStrList;
  while (UniqueElementNum(resultSubStrList) < K) {
    MakeSubstr(str, minC, resultSubStrList);
    minC = SearchMinChar(str, minC + 1);
  }

  sort(begin(resultSubStrList), end(resultSubStrList));
  vector<tuple<string, LL>> eachElementNum;
  EachElementNum(resultSubStrList, eachElementNum);
  string result = get<0>(eachElementNum[K - 1]);

  cout << result;

  return 0;
}

Fixed submission:
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;

using LL = long long;
using ULL = unsigned long long;
constexpr int INF = 2147483647;
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};

// 以下はC++の練習のための便利プログラム　あんまり便利じゃないけど…
//------------------------------------------便利型----------------------------------------------
// 二次元の点
// TODO map,setのほうが楽かも
template <typename T> struct Point2D {
  T x;
  T y;

  friend ostream &operator<<(ostream &os, const Point2D<T> &point);

  bool operator<(const Point2D &right) const {
    return (this->x == right.x) ? (this->y > right.y) : (this->x > right.x);
  }
};

ostream &operator<<(ostream &os, const Point2D<int> &point) {
  os << "(" << point.x << ',' << point.y << ")";
  return os;
}

// 長くて読みづらかったのでエイリアステンプレートに
template <class T> using StdAlloc = std::allocator<T>;

// 簡単な２次元配列
// Tにboolを使うとおかしくなるので、bitset<1>を使うこと
template <class T> class Array2D {
public:
  struct Array2DAccessor {
    LL h;
    LL w;

    Array2DAccessor operator+(const Array2DAccessor &right) const {
      return {h + right.h, w + right.w};
    }

    const static initializer_list<Array2DAccessor> UpDownLeftRight;
  };

public:
  Array2D(size_t height, size_t width, T init) {
    data = vector<vector<T>>(height, vector<T>(width, init));
  }

  // ループ　インデックスなし
  void ForEach(function<void(T &)> func) {
    for (auto &row : data) {
      for (T &column : row) {
        func(column);
      }
    }
  }

  // template<class FUNC>
  // void ForEach(FUNC func)
  //{
  //	for (auto& row : data) {
  //		for (T& column : row) {
  //			func(column);
  //		}
  //	}
  // }

  ////ループ　インデックスあり、return条件あり
  ////作ってみたけどめっちゃ使いにくい…
  // void ForEach(	//function<void(ULL, ULL, T&)> func,
  //				function<bool()> IsReturnAndClosureW = []() {return false;
  //}, 				function<bool()> IsReturnAndClosureH = []() {return false; }
  //			)
  //{
  //	for (ULL h = 0ULL; h < data.size(); h++) {
  //		if (IsReturnAndClosureW(h, w, data[h][w])) {
  //			continue;
  //		}
  //		for (ULL w = 0ULL; w < data[h].size(); w++) {
  //			if (IsReturnAndClosureH(h, w, data[h][w])) {
  //				break;
  //			}
  //			//func(h, w, data[h][w]);
  //		}
  //	}
  // }

  ULL GetHeight() { return data.size(); }

  ULL GetWidth() { return data.front().size(); }

  template <class INDEX> vector<T> &operator[](INDEX indx) {
    return data[indx];
  }

  bool IsValid(const Array2DAccessor &indx) const {
    return 0LL <= indx.h && indx.h < (unsigned)data.size() && 0LL <= indx.w &&
           indx.w < (unsigned)data.front().size();
  }

public:
  vector<vector<T>> data;
};

template <class T>
const initializer_list<typename Array2D<T>::Array2DAccessor>
    Array2D<T>::Array2DAccessor::UpDownLeftRight = {
        {0LL, 1LL}, {0LL, -1LL}, {-1LL, 0LL}, {1LL, 0LL}};

//------------------------------------------便利型----------------------------------------------

// 深さ優先探索
// 再帰で実装するとStack Overflowになる…　Atcoderのスタックサイズはいくつ？
template <class Container, class Accessor>
tuple<ULL> DepthFirstSearch(
    Container &field, const Accessor &start,
    const initializer_list<Accessor> &searchDir,
    const function<void(const Accessor &, Container &)> &Work,
    const function<bool(const Accessor &, Container &)> &IsSearch) {
  tuple<ULL> info = make_tuple(0); // 探索の情報　てきとー
  queue<Accessor> taskQueue;
  taskQueue.push(start);

  while (!taskQueue.empty()) {
    const auto task = taskQueue.front();
    taskQueue.pop();

    // 各方向へ探索
    for (const auto &df : searchDir) {
      auto indx = task + df;
      if (!IsSearch(indx, field)) {
        continue;
      }

      Work(indx, field);

      // 探索に関する各種情報を更新
      get<0>(info)++;
      taskQueue.push(indx);
    }
  }

  return info;
}

//-----------------------------------------便利関数---------------------------------------------
// デバッグ用乱数
// random_device rnd;
// mt19937 mt(0);
// uniform_int_distribution<int> rand10_9(0, 10);
// for (unsigned i = 0; i < N; i++) {
//	numbers[i] = (long long)(rand10_9(mt) - 10);
//	//numbers[i] = 0;
//}

// コンテナに格納された要素がそれぞれいくつあるか
// 処理時間は遅い
template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void EachElementNum(const Container<T> &container, map<T, LL> &numberCounts) {
  for (const auto &data : container) {
    numberCounts[data] =
        (numberCounts.count(data) == 0) ? 1 : ++numberCounts[data];
  }
}

template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void EachElementNum(const Container<T> &container,
                    vector<tuple<T, LL>> &numberCounts) {
  map<T, LL> eachElementNum;
  EachElementNum(container, eachElementNum);
  for (const auto &info : eachElementNum) {
    numberCounts.emplace_back(make_tuple(info.first, info.second));
  }
}

// 累積和
template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void PrefixSum(Container<T> &c) {
  for (auto now = begin(c) + 1, prev = begin(c); now != end(c); now++, prev++) {
    *now += +*prev;
  }
}

// ユニークな要素数
template <class T> unsigned long long UniqueElementNum(const vector<T> &data) {
  auto copy = data;

  sort(begin(copy), end(copy));
  copy.erase(unique(begin(copy), end(copy)), end(copy));

  return copy.size();

  // set<unsigned long long>(begin(copy), end(copy)).size();
  // //１行版　マクロにしても良い
}

// ある閉区間の範囲内かどうか　やっぱり使いづらい
template <class T> bool IsInClose(T x, T min, T max) {
  return (min <= x && x <= max);
}

// 値が昇順になっているか
template <class T> bool IsInOrder(const T &value1, const T &value2) {
  return !(value2 < value1);
}

template <class T>
bool IsInOrder(const T &value1, const T &value2, const T &value3) {
  return !(value2 < value1) && !(value3 < value2);
}

template <class T>
bool IsInOrder(const T &value1, const T &value2, const T &value3,
               const T &value4) {
  return !(value2 < value1) && !(value3 < value2) && !(value4 < value3);
}

// 値が範囲内かどうか
template <class T>
inline bool IsInRange(const T &min, const T &value, const T &max) {
  return IsInOrder(min, value, max);
}

// 最小公倍数 #TODO template化
long long gcd(long long a, long long b) {
  long long c;

  if (a < b) {
    a += b;
    b = a - b;
    a -= b;
  }

  while (b != 0) {
    c = a % b;
    a = b;
    b = c;
  }

  return a;
}

// 素数かどうか #TODO template化
bool IsPrime(ULL num) {
  if (num < 2)
    return false;
  else if (num == 2)
    return true;
  else if (num % 2 == 0)
    return false; // 偶数はあらかじめ除く

  double sqrtNum = sqrt(num);
  for (ULL i = 3; i <= sqrtNum; i += 2) {
    if (num % i == 0) {
      // 素数ではない
      return false;
    }
  }

  // 素数である
  return true;
}

// 素因数分解　試し割り（sqrt(n)まで）
// もっと早い方法もあるらしい…
void DecomposePrime(ULL n, vector<tuple<ULL, ULL>> &result) {
  vector<ULL> primeList;

  // 割る数の初期値
  ULL a = 2;

  // √n ≧ a ( n ≧ a * a ) の間ループ処理
  while (n >= a * a) {
    // a で割り切れたら、a は素因数
    // そして、割られる数を a で割る
    // a で割り切れなかったら、 a を 1 増加させる
    if (n % a == 0) {
      primeList.emplace_back(a);
      n /= a;
    } else {
      a++;
    }
  }
  // 最後に残った n は素因数
  primeList.emplace_back(n);

  // 素因数がそれぞれいくつあるかを調べる
  set<ULL> uniquePrimeList(begin(primeList), end(primeList));
  for (const auto &p : uniquePrimeList) {
    ULL primeNum = count(begin(primeList), end(primeList), p);
    result.emplace_back(make_tuple(p, primeNum));
  }
}

// n個からr個取り出す組み合わせの数
template <typename Type> Type nCr(Type n, Type r) {
  Type ans = 1;
  for (Type i = n; i > n - r; --i) {
    ans = ans * i;
  }
  for (Type i = 1; i < r + 1; ++i) {
    ans = ans / i;
  }
  return ans;
}

// 新しい方に対応したい場合、以下を参考にする
// コンテナへ要素を追加
// プリミティブ型など
template <class Num, class Container>
void InitContainer(Num num, Container &container) {
  container.resize(num);
  for (auto &d : container) {
    cin >> d;
  }
}

// コンテナへ要素を追加
// Container<Point2D<T>>で特殊化　読みにくい…　マクロにする？
template <class Num,
          template <class T, class Allocator = StdAlloc<T>> class Container,
          class T2>
void InitContainer(Num num, Container<Point2D<T2>> &firstContainer) {
  firstContainer.resize(num);
  for (auto &d : firstContainer) {
    cin >> d.x >> d.y;
  }
}

// コンテナへ要素を追加　を呼び出す処理
template <class Num, class First, class... Rest>
void InitContainer(Num num, First &first, Rest &...rest) {
  InitContainer(num, first);
  InitContainer(num, rest...);
}

// 要素数Nと各要素をコンテナに格納
// コンテナを複数個取れるようにしてみた　テンプレートの練習
template <class Num, class... Container>
void InitNumAndContainer(Num &num, Container &...container) {
  cin >> num;
  InitContainer(num, container...);
}

// コンテナの内容をstreamへ出力
// 今はてきとーにcoutへ改行しながら　果たしてこの書き方は便利なのか…？
// #TODO 引数増やしたりオーバーロード増やしたり
template <template <class T, class Allocator = StdAlloc<T>> class Container,
          class T>
void ShowContainer(const Container<T> &container) {
  ostream_iterator<T> outItr(cout, "\n");
  copy(container.begin(), container.end(), outItr);
  cout << endl;
}

//-----------------------------------------便利関数---------------------------------------------

int main() {
  string str;
  ULL K;
  cin >> str >> K;

  auto SearchMinChar = [](const string &str, char minC) {
    char result = minC;
    for (const auto &s : str) {
      result = min(result, s);
    }

    return result;
  };

  auto MakeSubstr = [](const string &str, char minC,
                       vector<string> &resultSubStrList) {
    vector<int> minCIndxList;

    for (auto s = str.rbegin(); s != str.rend(); s++) {
      if (*s != minC) {
        continue;
      }

      int fromEndIndx = distance(str.rbegin(), s);
      minCIndxList.emplace_back((str.size() - 1) - fromEndIndx);
    }

    vector<string> subStrList(minCIndxList.size(), "");
    for (int i = 0; i < 5; i++) { // #TODO 5はてきとう
      for (int j = 0; j < subStrList.size(); j++) {
        int indx = minCIndxList[j];
        if (indx + i >= str.size()) {
          continue;
        }

        subStrList[j] += str[indx + i];
        resultSubStrList.emplace_back(subStrList[j]);
      }
    }
  };

  char minC = SearchMinChar(str, 'z');
  vector<string> resultSubStrList;
  while (UniqueElementNum(resultSubStrList) < K) {
    MakeSubstr(str, minC, resultSubStrList);
    minC++; // = SearchMinChar(str, minC + 1);
  }

  sort(begin(resultSubStrList), end(resultSubStrList));
  vector<tuple<string, LL>> eachElementNum;
  EachElementNum(resultSubStrList, eachElementNum);
  string result = get<0>(eachElementNum[K - 1]);

  cout << result;

  return 0;
}