Problem p04042 (C++)

Buggy submission (status: Time Limit Exceeded):
#pragma GCC optimize("O3")
#pragma GCC target("sse4")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef pair<ld, ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T>
using Tree =
    tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for (int i = 0; i < (a); i++)
#define FORd(i, a, b) for (int i = (b)-1; i >= (a); i--)
#define F0Rd(i, a) for (int i = (a)-1; i >= 0; i--)
#define trav(a, x) for (auto &a : x)

#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound

#define sz(x) (int)x.size()
#define beg(x) x.begin()
#define en(x) x.end()
#define all(x) beg(x), en(x)
#define resz resize

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;
const ld PI = 4 * atan((ld)1);

template <class T> void ckmin(T &a, T b) { a = min(a, b); }
template <class T> void ckmax(T &a, T b) { a = max(a, b); }

namespace io {
// TYPE ID (StackOverflow)

template <class T> struct like_array : is_array<T> {};
template <class T, size_t N> struct like_array<array<T, N>> : true_type {};
template <class T> struct like_array<vector<T>> : true_type {};
template <class T> bool is_like_array(const T &a) {
  return like_array<T>::value;
}

// I/O

void setIn(string s) { freopen(s.c_str(), "r", stdin); }
void setOut(string s) { freopen(s.c_str(), "w", stdout); }
void setIO(string s = "") {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  if (sz(s)) {
    setIn(s + ".in"), setOut(s + ".out");
  }
}

// INPUT

template <class T> void re(T &x) { cin >> x; }
template <class Arg, class... Args> void re(Arg &first, Args &...rest);
void re(double &x) {
  string t;
  re(t);
  x = stod(t);
}
void re(ld &x) {
  string t;
  re(t);
  x = stold(t);
}

template <class T> void re(complex<T> &x);
template <class T1, class T2> void re(pair<T1, T2> &p);
template <class T> void re(vector<T> &a);
template <class T, size_t SZ> void re(array<T, SZ> &a);

template <class Arg, class... Args> void re(Arg &first, Args &...rest) {
  re(first);
  re(rest...);
}
template <class T> void re(complex<T> &x) {
  T a, b;
  re(a, b);
  x = cd(a, b);
}
template <class T1, class T2> void re(pair<T1, T2> &p) { re(p.f, p.s); }
template <class T> void re(vector<T> &a) { F0R(i, sz(a)) re(a[i]); }
template <class T, size_t SZ> void re(array<T, SZ> &a) { F0R(i, SZ) re(a[i]); }

// OUTPUT

template <class T1, class T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &a) {
  os << '{' << a.f << ", " << a.s << '}';
  return os;
}
template <class T> ostream &printArray(ostream &os, const T &a, int SZ) {
  os << '{';
  F0R(i, SZ) {
    if (i) {
      os << ", ";
      if (is_like_array(a[i]))
        cout << "\n";
    }
    os << a[i];
  }
  os << '}';
  return os;
}
template <class T, size_t SZ>
ostream &operator<<(ostream &os, const array<T, SZ> &a) {
  return printArray(os, a, SZ);
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &a) {
  return printArray(os, a, sz(a));
}
template <class T> ostream &operator<<(ostream &os, const set<T> &a) {
  os << vector<T>(all(a));
  return os;
}
template <class T1, class T2>
ostream &operator<<(ostream &os, const map<T1, T2> &a) {
  os << vector<pair<T1, T2>>(all(a));
  return os;
}

template <class T> void pr(const T &x) { cout << x << '\n'; }
template <class Arg, class... Args>
void pr(const Arg &first, const Args &...rest) {
  cout << first << ' ';
  pr(rest...);
}
} // namespace io

using namespace io;

namespace Z {
vi z(string s) {
  int N = sz(s);
  s += '#';
  vi ans(N);
  ans[0] = N;
  while (s[1 + ans[1]] == s[ans[1]])
    ans[1]++;

  int L = 1, R = ans[1];
  FOR(i, 2, N) {
    if (i <= R)
      ans[i] = min(R - i + 1, ans[i - L]);
    while (s[i + ans[i]] == s[ans[i]])
      ans[i]++;
    if (i + ans[i] - 1 > R)
      L = i, R = i + ans[i] - 1;
  }
  return ans;
}

vi get(string a, string b) { // find prefixes of a in b
  string s = a + "@" + b;
  vi t = z(s);
  return vi(t.begin() + sz(a) + 1, t.end());
}
}; // namespace Z

int N, K;
bitset<10001> ok[2001];
string s[2001];
int dp[10001];
string cur, zz;
vi z;

inline int cmp(char a, char b) {
  // assert (a != b);
  if (a < b)
    return -1;
  return 1;
}

inline string get(pi x) {
  string ret = cur.substr(0, x.f);
  if (x.s)
    ret += zz;
  return ret;
}

inline int cmp(string a, string b) {
  if (b.substr(0, sz(a)) == a)
    return 0;
  if (a < b)
    return -1;
  return 1;
}

inline int cmptest(pi a, pi b) {
  if (a == b)
    return 0;
  if (a.s == 0) {
    if (b.s == 0 || a.f <= b.f)
      return 0;
    int com = min(z[sz(zz) + b.f], a.f - b.f);
    if (com == a.f - b.f)
      return 0;
    return cmp(cur[b.f + com], zz[com]);
  } else {
    if (b.s == 0) {
      // pr("HI");
      int com = min(z[sz(zz) + a.f], min(b.f - a.f, sz(zz)));
      if (com == sz(zz))
        return 0;
      return cmp(zz[com], cur[a.f + com]);
    }
    int com = min(z[sz(zz) + a.f], min(b.f - a.f, sz(zz)));
    if (com == sz(zz))
      return 0;
    if (com < b.f - a.f)
      return cmp(zz[com], cur[a.f + com]);
    com = min(z[b.f - a.f], sz(zz) - (b.f - a.f));
    if (com == sz(zz) - (b.f - a.f))
      return 0;
    return cmp(zz[b.f - a.f + com], zz[com]);
  }
}

inline int cmp(pi a, pi b) { // len(a) <= len(b)
  if (cmp(get(a), get(b)) != cmptest(a, b)) {
    pr(a, b, zz, cur, cmp(get(a), get(b)), cmptest(a, b));
    exit(0);
  }
  return cmptest(a, b);
}

void tri(int ind) {
  zz = s[ind];
  z = Z::z(zz + cur);
  F0R(i, 10000) z.pb(0);
  F0Rd(i, K + 1 - sz(s[ind])) if (dp[i] ==
                                  0) if (dp[i + sz(zz)] == -1 ||
                                         cmp(mp(i, 1), mp(i + sz(s[ind]), 0)) ==
                                             -1) dp[i + sz(zz)] = 1;

  F0R(i, K + 1) if (!ok[ind + 1][i]) dp[i] = -1;
  vpi vals;
  F0R(i, K + 1) if (dp[i] != -1) {
    pi val = {i - sz(zz) * dp[i], dp[i]};
    while (sz(vals) && cmp(vals.back(), val) == 1)
      vals.pop_back();
    if (sz(vals) && cmp(vals.back(), val) == -1)
      continue;
    vals.pb(val);
  }
  F0R(i, K + 1) dp[i] = -1;
  trav(a, vals) dp[a.f + a.s * sz(zz)] = 0;
  cur = get(vals.back());
}

int main() {
  // you should actually read the stuff at the bottom
  setIO();
  re(N, K);
  F0R(i, N) re(s[i]);
  ok[N][K] = 1;
  F0Rd(i, N) ok[i] = ok[i + 1] | (ok[i + 1] >> sz(s[i]));
  assert(ok[0][0]);
  FOR(i, 1, 10001) dp[i] = -1;
  F0R(i, N) tri(i);
  pr(cur);
  // F0R(i,K+1) cout << ok[0][i] << " ";
  // you should actually read the stuff at the bottom
}

/* stuff you should look for
 * int overflow, array bounds
 * special cases (n=1?), set tle
 * do smth instead of nothing and stay organized
 */

Fixed submission:
#pragma GCC optimize("O3")
#pragma GCC target("sse4")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef pair<ld, ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T>
using Tree =
    tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for (int i = 0; i < (a); i++)
#define FORd(i, a, b) for (int i = (b)-1; i >= (a); i--)
#define F0Rd(i, a) for (int i = (a)-1; i >= 0; i--)
#define trav(a, x) for (auto &a : x)

#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound

#define sz(x) (int)x.size()
#define beg(x) x.begin()
#define en(x) x.end()
#define all(x) beg(x), en(x)
#define resz resize

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;
const ld PI = 4 * atan((ld)1);

template <class T> void ckmin(T &a, T b) { a = min(a, b); }
template <class T> void ckmax(T &a, T b) { a = max(a, b); }

namespace io {
// TYPE ID (StackOverflow)

template <class T> struct like_array : is_array<T> {};
template <class T, size_t N> struct like_array<array<T, N>> : true_type {};
template <class T> struct like_array<vector<T>> : true_type {};
template <class T> bool is_like_array(const T &a) {
  return like_array<T>::value;
}

// I/O

void setIn(string s) { freopen(s.c_str(), "r", stdin); }
void setOut(string s) { freopen(s.c_str(), "w", stdout); }
void setIO(string s = "") {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  if (sz(s)) {
    setIn(s + ".in"), setOut(s + ".out");
  }
}

// INPUT

template <class T> void re(T &x) { cin >> x; }
template <class Arg, class... Args> void re(Arg &first, Args &...rest);
void re(double &x) {
  string t;
  re(t);
  x = stod(t);
}
void re(ld &x) {
  string t;
  re(t);
  x = stold(t);
}

template <class T> void re(complex<T> &x);
template <class T1, class T2> void re(pair<T1, T2> &p);
template <class T> void re(vector<T> &a);
template <class T, size_t SZ> void re(array<T, SZ> &a);

template <class Arg, class... Args> void re(Arg &first, Args &...rest) {
  re(first);
  re(rest...);
}
template <class T> void re(complex<T> &x) {
  T a, b;
  re(a, b);
  x = cd(a, b);
}
template <class T1, class T2> void re(pair<T1, T2> &p) { re(p.f, p.s); }
template <class T> void re(vector<T> &a) { F0R(i, sz(a)) re(a[i]); }
template <class T, size_t SZ> void re(array<T, SZ> &a) { F0R(i, SZ) re(a[i]); }

// OUTPUT

template <class T1, class T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &a) {
  os << '{' << a.f << ", " << a.s << '}';
  return os;
}
template <class T> ostream &printArray(ostream &os, const T &a, int SZ) {
  os << '{';
  F0R(i, SZ) {
    if (i) {
      os << ", ";
      if (is_like_array(a[i]))
        cout << "\n";
    }
    os << a[i];
  }
  os << '}';
  return os;
}
template <class T, size_t SZ>
ostream &operator<<(ostream &os, const array<T, SZ> &a) {
  return printArray(os, a, SZ);
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &a) {
  return printArray(os, a, sz(a));
}
template <class T> ostream &operator<<(ostream &os, const set<T> &a) {
  os << vector<T>(all(a));
  return os;
}
template <class T1, class T2>
ostream &operator<<(ostream &os, const map<T1, T2> &a) {
  os << vector<pair<T1, T2>>(all(a));
  return os;
}

template <class T> void pr(const T &x) { cout << x << '\n'; }
template <class Arg, class... Args>
void pr(const Arg &first, const Args &...rest) {
  cout << first << ' ';
  pr(rest...);
}
} // namespace io

using namespace io;

namespace Z {
vi z(string s) {
  int N = sz(s);
  s += '#';
  vi ans(N);
  ans[0] = N;
  while (s[1 + ans[1]] == s[ans[1]])
    ans[1]++;

  int L = 1, R = ans[1];
  FOR(i, 2, N) {
    if (i <= R)
      ans[i] = min(R - i + 1, ans[i - L]);
    while (s[i + ans[i]] == s[ans[i]])
      ans[i]++;
    if (i + ans[i] - 1 > R)
      L = i, R = i + ans[i] - 1;
  }
  return ans;
}

vi get(string a, string b) { // find prefixes of a in b
  string s = a + "@" + b;
  vi t = z(s);
  return vi(t.begin() + sz(a) + 1, t.end());
}
}; // namespace Z

int N, K;
bitset<10001> ok[2001];
string s[2001];
int dp[10001];
string cur, zz;
vi z;

inline int cmp(char a, char b) {
  // assert (a != b);
  if (a < b)
    return -1;
  return 1;
}

inline string get(pi x) {
  string ret = cur.substr(0, x.f);
  if (x.s)
    ret += zz;
  return ret;
}

inline int cmp(string a, string b) {
  if (b.substr(0, sz(a)) == a)
    return 0;
  if (a < b)
    return -1;
  return 1;
}

inline int cmptest(pi a, pi b) {
  if (a == b)
    return 0;
  if (a.s == 0) {
    if (b.s == 0 || a.f <= b.f)
      return 0;
    int com = min(z[sz(zz) + b.f], a.f - b.f);
    if (com == a.f - b.f)
      return 0;
    return cmp(cur[b.f + com], zz[com]);
  } else {
    if (b.s == 0) {
      // pr("HI");
      int com = min(z[sz(zz) + a.f], min(b.f - a.f, sz(zz)));
      if (com == sz(zz))
        return 0;
      return cmp(zz[com], cur[a.f + com]);
    }
    int com = min(z[sz(zz) + a.f], min(b.f - a.f, sz(zz)));
    if (com == sz(zz))
      return 0;
    if (com < b.f - a.f)
      return cmp(zz[com], cur[a.f + com]);
    com = min(z[b.f - a.f], sz(zz) - (b.f - a.f));
    if (com == sz(zz) - (b.f - a.f))
      return 0;
    return cmp(zz[b.f - a.f + com], zz[com]);
  }
}

inline int cmp(pi a, pi b) { return cmptest(a, b); }

void tri(int ind) {
  zz = s[ind];
  z = Z::z(zz + cur);
  F0R(i, 10000) z.pb(0);
  F0Rd(i, K + 1 - sz(s[ind])) if (dp[i] ==
                                  0) if (dp[i + sz(zz)] == -1 ||
                                         cmp(mp(i, 1), mp(i + sz(s[ind]), 0)) ==
                                             -1) dp[i + sz(zz)] = 1;

  F0R(i, K + 1) if (!ok[ind + 1][i]) dp[i] = -1;
  vpi vals;
  F0R(i, K + 1) if (dp[i] != -1) {
    pi val = {i - sz(zz) * dp[i], dp[i]};
    while (sz(vals) && cmp(vals.back(), val) == 1)
      vals.pop_back();
    if (sz(vals) && cmp(vals.back(), val) == -1)
      continue;
    vals.pb(val);
  }
  F0R(i, K + 1) dp[i] = -1;
  trav(a, vals) dp[a.f + a.s * sz(zz)] = 0;
  cur = get(vals.back());
}

int main() {
  // you should actually read the stuff at the bottom
  setIO();
  re(N, K);
  F0R(i, N) re(s[i]);
  ok[N][K] = 1;
  F0Rd(i, N) ok[i] = ok[i + 1] | (ok[i + 1] >> sz(s[i]));
  assert(ok[0][0]);
  FOR(i, 1, 10001) dp[i] = -1;
  F0R(i, N) tri(i);
  pr(cur);
  // F0R(i,K+1) cout << ok[0][i] << " ";
  // you should actually read the stuff at the bottom
}

/* stuff you should look for
 * int overflow, array bounds
 * special cases (n=1?), set tle
 * do smth instead of nothing and stay organized
 */