Problem p01973 (C++) — buggy submission, verdict: Time Limit Exceeded


#if 1
#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <cstdint>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

auto &in = std::cin;
auto &out = std::cout;
#define all(C) std::begin(C), std::end(C)
const double PI =
    3.141592653589793238462643383279502884197169399375105820974944;

struct Trie {
  Trie *node[26] = {}; // 各アルファベットへの子のポインタ
  bool black = false;  // この文字列の頂点が黒かどうか
  Trie() : node() {}
  void add(const char *str) {
    if (*str == '\\0') {
      black = true;
      return;
    }
    int nxt = *str - 'a';
    if (!node[nxt]) {
      node[nxt] = new Trie;
    }
    node[nxt]->add(str + 1);
  }
  // strを見つけて、最も浅い高さにいるblackな頂点の高さを返す
  // ない場合は-1
  int search(const char *str) {
    if (black)
      return 0;
    if (*str == '\\0')
      return -1;
    int nxt = *str - 'a';
    if (!node[nxt]) {
      return -1;
    }
    int res = node[nxt]->search(str + 1);
    if (res == -1)
      return -1;
    return res + 1;
  }
};

using namespace std;
using ULL = unsigned long long;
const ULL P = 1000000007;
struct RollHash {
  string str;
  vector<ULL> imos; //[0,i)までのハッシュがあるよ
  vector<ULL> pvar; // Pのi乗が入っているよ
  RollHash(string str) : str(str) {
    imos.push_back(0);
    for (int i = 0; i < (int)str.size(); ++i) {
      imos.push_back(imos.back() * P + str[i]);
    }
    pvar.push_back(1);
    for (int i = 0; i < (int)str.size(); ++i) {
      pvar.push_back(pvar.back() * P);
    }
  }
  //[x,y)までのハッシュを返すよ
  ULL getHash(int x, int y) { return imos[y] - imos[x] * pvar[y - x]; }
};

Trie trie;
std::string S;
std::string S_rever;
std::vector<std::string> p_small;
// std::vector<std::string> p_large;
std::vector<RollHash> p_RH;
int32_t N;
int32_t DP_[100010];
int32_t *DP = DP_ + 2; //[j]はjに*を入れたときの最小値
int main() {
  using std::endl;
  in.sync_with_stdio(false);
  out.sync_with_stdio(false);
  in.tie(nullptr);
  out.tie(nullptr);

  in >> S >> N;
  S_rever = S;
  std::reverse(S_rever.begin(), S_rever.end());
  for (int32_t i = 0; i < N; i++) {
    std::string input;
    in >> input;
    if (input.size() <= 317) {
      p_small.emplace_back(std::move(input));
    } else {
      // p_large.emplace_back(std::move(input));
      p_RH.emplace_back(std::move(input));
    }
  }

  // 小さいほうをとらい木に突っ込む
  for (auto &i : p_small) {
    std::reverse(i.begin(), i.end());
    trie.add(i.c_str());
  }

  RollHash S_RH{S};
  auto iter = S_rever.c_str() + S_rever.size() - 1;
  int32_t ok_begin = -1;
  DP[-1] = 0;
  for (int32_t i = 0; i < S.size(); i++) {
    // i追加
    DP[i] = DP[ok_begin] + 1;

    // OKを移動
    int res = trie.search(iter);
    if (res == -1) {
    } else {
      ok_begin = std::max(ok_begin, i - res + 1);
    }
    --iter;

    for (auto &P : p_RH) {
      int size = P.str.size();
      if (i - size + 1 < 0) {
        continue;
      }
      auto bace = S_RH.getHash(i - size + 1, i + 1);
      auto other = P.getHash(0, size);
      if (bace == other) {
        ok_begin = std::max(ok_begin, i - size + 1);
      }
    }
  }

  int32_t min_ = 10000000;
  for (int32_t i = ok_begin; i < (int)S.size(); i++) {
    min_ = std::min(min_, DP[i]);
  }
  out << min_ << endl;

  return 0;
}
#endif


Error: TLE

Fixed submission:


#if 1
#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <cstdint>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

auto &in = std::cin;
auto &out = std::cout;
#define all(C) std::begin(C), std::end(C)
const double PI =
    3.141592653589793238462643383279502884197169399375105820974944;

struct Trie {
  Trie *node[26];     // 各アルファベットへの子のポインタ
  bool black = false; // この文字列の頂点が黒かどうか
  Trie() : node() {}
  void add(const char *str) {
    if (*str == '\\0') {
      black = true;
      return;
    }
    int nxt = *str - 'a';
    if (!node[nxt]) {
      node[nxt] = new Trie;
    }
    node[nxt]->add(str + 1);
  }
  // strを見つけて、最も浅い高さにいるblackな頂点の高さを返す
  // ない場合は-1
  int search(const char *str) {
    if (black)
      return 0;
    if (*str == '\\0')
      return -1;
    int nxt = *str - 'a';
    if (!node[nxt]) {
      return -1;
    }
    int res = node[nxt]->search(str + 1);
    if (res == -1)
      return -1;
    return res + 1;
  }
};

using namespace std;
using ULL = unsigned long long;
const ULL P = 1000000007;
struct RollHash {
  string str;
  vector<ULL> imos; //[0,i)までのハッシュがあるよ
  vector<ULL> pvar; // Pのi乗が入っているよ
  RollHash(string str) : str(str) {
    imos.push_back(0);
    for (int i = 0; i < (int)str.size(); ++i) {
      imos.push_back(imos.back() * P + str[i]);
    }
    pvar.push_back(1);
    for (int i = 0; i < (int)str.size(); ++i) {
      pvar.push_back(pvar.back() * P);
    }
  }
  //[x,y)までのハッシュを返すよ
  ULL getHash(int x, int y) { return imos[y] - imos[x] * pvar[y - x]; }
};

Trie trie;
std::string S;
std::string S_rever;
std::vector<std::string> p_small;
// std::vector<std::string> p_large;
std::vector<RollHash> p_RH;
int32_t N;
int32_t DP_[100010];
int32_t *DP = DP_ + 2; //[j]はjに*を入れたときの最小値
int main() {
  using std::endl;
  in.sync_with_stdio(false);
  out.sync_with_stdio(false);
  in.tie(nullptr);
  out.tie(nullptr);

  in >> S >> N;
  S_rever = S;
  std::reverse(S_rever.begin(), S_rever.end());
  for (int32_t i = 0; i < N; i++) {
    std::string input;
    in >> input;
    if (false) { // if (input.size() <= 317) {
      p_small.emplace_back(std::move(input));
    } else {
      // p_large.emplace_back(std::move(input));
      p_RH.emplace_back(std::move(input));
    }
  }

  // 小さいほうをとらい木に突っ込む
  for (auto &i : p_small) {
    std::reverse(i.begin(), i.end());
    trie.add(i.c_str());
  }

  RollHash S_RH{S};
  auto iter = S_rever.c_str() + S_rever.size() - 1;
  int32_t ok_begin = -1;
  DP[-1] = 0;
  for (int32_t i = 0; i < S.size(); i++) {
    // i追加
    DP[i] = DP[ok_begin] + 1;

    // OKを移動
    int res = trie.search(iter);
    if (res == -1) {
    } else {
      ok_begin = i - res + 1;
    }
    --iter;

    for (auto &P : p_RH) {
      int size = P.str.size();
      if (i - size + 1 < 0) {
        continue;
      }
      auto bace = S_RH.getHash(i - size + 1, i + 1);
      auto other = P.getHash(0, size);
      if (bace == other) {
        ok_begin = std::max(ok_begin, i - size + 1);
      }
    }
  }

  int32_t min_ = 10000000;
  for (int32_t i = ok_begin; i < (int)S.size(); i++) {
    min_ = std::min(min_, DP[i]);
  }
  out << min_ << endl;

  return 0;
}
#endif