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

#define _CRT_SECURE_NO_WARNINGS
#include <algorithm>
#include <assert.h>
#include <cmath>
#include <complex>
#include <ctime>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <new>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <time.h>
#include <vector>
#define BIT(nr) (1ULL << (nr))
// #define int long long
#define ll long long
#define double complex<long double>
#define mod 1000000007
#define MAXN (int)1e+5 * 2 + 1
#define LL_MAX 9223372036854775807
#define LL_HALFMAX 9223372036854775807 / 2
#define MIN -(9223372036854775807 / 2)
#define REP(i, a, n) for (int i = (a); i < (int)(n); i++)
#define rep(i, n) REP(i, 0, n)
#define FOR(it, c)                                                             \\
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
#define ALLOF(c) (c).begin(), (c).end()
#define REPS(i, x) for (int i = 1; i <= (int)(x); i++)
#define RREP(i, x) for (int i = ((int)(x)-1); i >= 0; i--)
#define RREPS(i, x) for (int i = ((int)(x)); i > 0; i--)
#define repl(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define mp make_pair
template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}

using namespace std;

namespace mmlib {

template <typename T1, typename T2> struct Pair {
  Pair() {}
  Pair(const Pair &) = default;
  Pair(Pair &&) = default;
  Pair &operator=(const Pair &) = default;
  Pair(const T1 &f, const T2 &s) : first(f), second(s) {}
  Pair(T1 &&f, T2 &&s) : first(f), second(s) {}

  T1 first;
  T2 second;
};

template <typename T, unsigned int N> class Vector {
public:
  template <class Itr> void assign(Itr first, Itr last) {
    size_ = 0;
    while (first != last) {
      assert(size_ < N);
      m_[size_++] = *first++;
    }
  }

  void assign(size_t n, const T &v) {
    assert(n < N);
    size_ = n;
    while (n--)
      m_[n] = v;
  }

  void assign(std::initializer_list<T> il) { assign(il.begin(), il.end()); }

  void resize(size_t n) {
    assert(0 <= n);
    assert(n < N);
    size_ = n;
  }

  T *begin() { return m_.begin(); };
  const T *begin() const { return m_.begin(); };

  T *end() { return m_.begin() + size_; };
  const T *end() const { return m_.begin() + size_; };

  void clear() { size_ = 0; };

  size_t size() const { return size_; };

  void push_back(const T &v) {
    assert(size_ < N);
    m_[size_++] = v;
  }

  void pop_back() {
    assert(size_ != 0);
    size_--;
  }

  T &front() {
    assert(0 < size_);
    return *m_.begin();
  }

  const T &front() const {
    assert(0 < size_);
    return *m_.begin();
  }

  T &back() {
    assert(0 < size_);
    return *(m_.begin() + size_ - 1);
  }

  const T &back() const {
    assert(0 < size_);
    return *(m_.begin() + size_ - 1);
  }

  T &operator[](size_t pos) {
    assert(pos < size_);
    return m_[pos];
  }

  const T &operator[](size_t pos) const {
    assert(pos < size_);
    return m_[pos];
  }

private:
  std::array<T, N> m_;
  uint32_t size_ = 0;
};

template <typename T, int N, class Compare = std::less<T>> class Ranking {
public:
  void on_rankout(std::function<void(const T &)> op) { on_pop_min_ = op; }

  bool is_rankin(const T &value) {
    return m_.size() < N ? true : Compare()(min_element(), value);
  }

  void push(const T &value) {
    m_.insert(value);
    if (size() == N) {
      on_pop_min_(min_element());
      pop_min();
    }
  }

  T min_element() {
    assert(!empty());
    return *m_.begin();
  }

  const T &min_element() const {
    assert(!empty());
    return *m_.begin();
  }

  T max_element() {
    assert(!empty());
    return *m_.rbegin();
  }

  const T &max_element() const {
    assert(!empty());
    return *m_.rbegin();
  }

  void pop_min() {
    // assert(!empty());
    // Work Around: g++ -pthread -DNDEBUG -march=haswell -std=c++14 ./main.cpp
    // -O2  build breaks Search Result
    if (empty()) {
      std::cerr << "Something Wrong." << std::endl;
    }
    m_.erase(m_.begin());
  }

  void pop_max() {
    assert(!empty());
    m_.erase(--m_.end());
  }

  bool empty() const { return m_.empty(); }

  size_t size() const { return m_.size(); }

  void clear() { m_.clear(); }

  const std::multiset<T> &data() const { return m_; }

private:
  std::multiset<T> m_;
  std::function<void(const T &)> on_pop_min_;
};

} // namespace mmlib

// 1-indexed にする
const int TYPES = 26;

class Node {
public:
  int score;
  // contests[i]: i日目に行われたコンテスト 1-indexed
  vector<uint8_t> contests;
  // last[i]: コンテストi が最後に行われた日 1-indexed
  vector<uint16_t> last;

  Node() : contests(1, 0), last(27, 0), score(0) {}

  // contestId を末尾に追加した時のスコアを計算する
  int chal(const vector<int> &c, const vector<vector<int>> s,
           uint8_t contestId) {
    int day = contests.size();
    int add = s[day][contestId];
    int beforeLast = last[contestId];
    last[contestId] = day;

    int sub = 0;
    REPS(i, TYPES) { sub += c[i] * (day - last[i]); }

    last[contestId] = beforeLast;
    return score + add - sub;
  }

  // contestId を末尾に追加する
  int add(const vector<int> &c, const vector<vector<int>> s,
          uint8_t contestId) {
    int day = contests.size();
    int add = s[day][contestId];
    last[contestId] = day;

    int sub = 0;
    REPS(i, TYPES) { sub += c[i] * (day - last[i]); }

    score = score + add - sub;
    contests.push_back(contestId);
    return score + add - sub;
  }

  bool operator<(const Node &right) const { return score < right.score; }
};

// 変数名は問題Aに準ずる、 t はコンテストの開催計画を表す
int CalcScore(const int &D, const vector<int> &c, const vector<vector<int>> s,
              const vector<int> &t, vector<int> *pOutResult) {
  assert(t.size() == pOutResult->size());

  int score = 0;
  vector<int> lastDay(TYPES + 1, 0);

  REPS(d, D) {
    int add = s[d][t[d]];
    lastDay[t[d]] = d;
    int sub = 0;

    REPS(i, TYPES) { sub += c[i] * (d - lastDay[i]); }
    score += add;
    score -= sub;
    pOutResult->at(d) = score;
  }

  return score;
}

Node ChokudaiSearch(const int &D, const vector<int> &c,
                    const vector<vector<int>> s) {
  const int BeamWidth = 1000;
  const int BeamDepth = D + 1;
  const int loopCnt = 1;
  Node tmpNode;

  mmlib::Ranking<Node, BeamWidth> chokudaiData[366];
  rep(i, 366) {
    chokudaiData[i].on_rankout([](Node n) {});
  }

  chokudaiData[0].push(Node());

  int startTime = clock();
  while (clock() - startTime < 170 * CLOCKS_PER_SEC / 100) {
    // rep(dum2, 100){
    //  1回の時間計測に対し loopcnt 回ループをまわす
    rep(dumm, loopCnt) {
      rep(i, 366) {
        // 最終日が終わってたらbreak
        if (i == D) {
          break;
        }
        auto &prev = chokudaiData[i];
        auto &next = chokudaiData[i + 1];

        if (prev.empty())
          continue;

        // 最高のノードをとってくる
        auto node = prev.max_element();
        prev.pop_max();

        // 全コンテストをためす
        REPS(contestId, TYPES) {
          int chalScore = node.chal(c, s, contestId);
          tmpNode.score = chalScore;
          if (next.is_rankin(tmpNode)) {
            tmpNode = node;
            tmpNode.add(c, s, contestId);
            next.push(tmpNode);
          }
        }
      }
    }
  }

  return chokudaiData[D].max_element();
}

signed main() {

  int D;
  cin >> D;

  vector<int> c(TYPES + 1, 0);
  vector<vector<int>> s(D + 1, vector<int>(TYPES + 1, 0));

  REPS(i, TYPES) { cin >> c[i]; }

  REPS(i, D) {
    REPS(j, TYPES) { cin >> s[i][j]; }
  }

  // Dにちめまで chokudai サーチをする
  auto res = ChokudaiSearch(D, c, s);

  REPS(i, D) { cout << (int)res.contests[i] << "\\n"; }

  return 0;
}

Error: TLE

Fixed submission:

#define _CRT_SECURE_NO_WARNINGS
#include <algorithm>
#include <assert.h>
#include <cmath>
#include <complex>
#include <ctime>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <new>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <time.h>
#include <vector>
#define BIT(nr) (1ULL << (nr))
// #define int long long
#define ll long long
#define double complex<long double>
#define mod 1000000007
#define MAXN (int)1e+5 * 2 + 1
#define LL_MAX 9223372036854775807
#define LL_HALFMAX 9223372036854775807 / 2
#define MIN -(9223372036854775807 / 2)
#define REP(i, a, n) for (int i = (a); i < (int)(n); i++)
#define rep(i, n) REP(i, 0, n)
#define FOR(it, c)                                                             \\
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); ++it)
#define ALLOF(c) (c).begin(), (c).end()
#define REPS(i, x) for (int i = 1; i <= (int)(x); i++)
#define RREP(i, x) for (int i = ((int)(x)-1); i >= 0; i--)
#define RREPS(i, x) for (int i = ((int)(x)); i > 0; i--)
#define repl(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define mp make_pair
template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}

using namespace std;

namespace mmlib {

template <typename T1, typename T2> struct Pair {
  Pair() {}
  Pair(const Pair &) = default;
  Pair(Pair &&) = default;
  Pair &operator=(const Pair &) = default;
  Pair(const T1 &f, const T2 &s) : first(f), second(s) {}
  Pair(T1 &&f, T2 &&s) : first(f), second(s) {}

  T1 first;
  T2 second;
};

template <typename T, unsigned int N> class Vector {
public:
  template <class Itr> void assign(Itr first, Itr last) {
    size_ = 0;
    while (first != last) {
      assert(size_ < N);
      m_[size_++] = *first++;
    }
  }

  void assign(size_t n, const T &v) {
    assert(n < N);
    size_ = n;
    while (n--)
      m_[n] = v;
  }

  void assign(std::initializer_list<T> il) { assign(il.begin(), il.end()); }

  void resize(size_t n) {
    assert(0 <= n);
    assert(n < N);
    size_ = n;
  }

  T *begin() { return m_.begin(); };
  const T *begin() const { return m_.begin(); };

  T *end() { return m_.begin() + size_; };
  const T *end() const { return m_.begin() + size_; };

  void clear() { size_ = 0; };

  size_t size() const { return size_; };

  void push_back(const T &v) {
    assert(size_ < N);
    m_[size_++] = v;
  }

  void pop_back() {
    assert(size_ != 0);
    size_--;
  }

  T &front() {
    assert(0 < size_);
    return *m_.begin();
  }

  const T &front() const {
    assert(0 < size_);
    return *m_.begin();
  }

  T &back() {
    assert(0 < size_);
    return *(m_.begin() + size_ - 1);
  }

  const T &back() const {
    assert(0 < size_);
    return *(m_.begin() + size_ - 1);
  }

  T &operator[](size_t pos) {
    assert(pos < size_);
    return m_[pos];
  }

  const T &operator[](size_t pos) const {
    assert(pos < size_);
    return m_[pos];
  }

private:
  std::array<T, N> m_;
  uint32_t size_ = 0;
};

template <typename T, int N, class Compare = std::less<T>> class Ranking {
public:
  void on_rankout(std::function<void(const T &)> op) { on_pop_min_ = op; }

  bool is_rankin(const T &value) {
    return m_.size() < N ? true : Compare()(min_element(), value);
  }

  void push(const T &value) {
    m_.insert(value);
    if (size() == N) {
      on_pop_min_(min_element());
      pop_min();
    }
  }

  T min_element() {
    assert(!empty());
    return *m_.begin();
  }

  const T &min_element() const {
    assert(!empty());
    return *m_.begin();
  }

  T max_element() {
    assert(!empty());
    return *m_.rbegin();
  }

  const T &max_element() const {
    assert(!empty());
    return *m_.rbegin();
  }

  void pop_min() {
    // assert(!empty());
    // Work Around: g++ -pthread -DNDEBUG -march=haswell -std=c++14 ./main.cpp
    // -O2  build breaks Search Result
    if (empty()) {
      std::cerr << "Something Wrong." << std::endl;
    }
    m_.erase(m_.begin());
  }

  void pop_max() {
    assert(!empty());
    m_.erase(--m_.end());
  }

  bool empty() const { return m_.empty(); }

  size_t size() const { return m_.size(); }

  void clear() { m_.clear(); }

  const std::multiset<T> &data() const { return m_; }

private:
  std::multiset<T> m_;
  std::function<void(const T &)> on_pop_min_;
};

} // namespace mmlib

// 1-indexed にする
const int TYPES = 26;

class Node {
public:
  int score;
  // contests[i]: i日目に行われたコンテスト 1-indexed
  vector<uint8_t> contests;
  // last[i]: コンテストi が最後に行われた日 1-indexed
  vector<uint16_t> last;

  Node() : contests(1, 0), last(27, 0), score(0) {}

  // contestId を末尾に追加した時のスコアを計算する
  int chal(const vector<int> &c, const vector<vector<int>> s,
           uint8_t contestId) {
    int day = contests.size();
    int add = s[day][contestId];
    int beforeLast = last[contestId];
    last[contestId] = day;

    int sub = 0;
    REPS(i, TYPES) { sub += c[i] * (day - last[i]); }

    last[contestId] = beforeLast;
    return score + add - sub;
  }

  // contestId を末尾に追加する
  int add(const vector<int> &c, const vector<vector<int>> s,
          uint8_t contestId) {
    int day = contests.size();
    int add = s[day][contestId];
    last[contestId] = day;

    int sub = 0;
    REPS(i, TYPES) { sub += c[i] * (day - last[i]); }

    score = score + add - sub;
    contests.push_back(contestId);
    return score + add - sub;
  }

  bool operator<(const Node &right) const { return score < right.score; }
};

// 変数名は問題Aに準ずる、 t はコンテストの開催計画を表す
int CalcScore(const int &D, const vector<int> &c, const vector<vector<int>> s,
              const vector<int> &t, vector<int> *pOutResult) {
  assert(t.size() == pOutResult->size());

  int score = 0;
  vector<int> lastDay(TYPES + 1, 0);

  REPS(d, D) {
    int add = s[d][t[d]];
    lastDay[t[d]] = d;
    int sub = 0;

    REPS(i, TYPES) { sub += c[i] * (d - lastDay[i]); }
    score += add;
    score -= sub;
    pOutResult->at(d) = score;
  }

  return score;
}

Node ChokudaiSearch(const int &D, const vector<int> &c,
                    const vector<vector<int>> s) {
  const int BeamWidth = 1000;
  const int BeamDepth = D + 1;
  const int loopCnt = 1;
  Node tmpNode;

  mmlib::Ranking<Node, BeamWidth> chokudaiData[366];
  rep(i, 366) {
    chokudaiData[i].on_rankout([](Node n) {});
  }

  chokudaiData[0].push(Node());

  int startTime = clock();
  while (clock() - startTime < 199 * CLOCKS_PER_SEC / 100) {
    // rep(dum2, 100){
    //  1回の時間計測に対し loopcnt 回ループをまわす
    rep(dumm, loopCnt) {
      rep(i, 366) {
        // 最終日が終わってたらbreak
        if (i == D) {
          break;
        }
        auto &prev = chokudaiData[i];
        auto &next = chokudaiData[i + 1];

        if (prev.empty())
          continue;

        // 最高のノードをとってくる
        auto node = prev.max_element();
        prev.pop_max();

        // 全コンテストをためす
        REPS(contestId, TYPES) {
          int chalScore = node.chal(c, s, contestId);
          tmpNode.score = chalScore;
          if (next.is_rankin(tmpNode)) {
            tmpNode = node;
            tmpNode.add(c, s, contestId);
            next.push(tmpNode);
          }
        }
      }
    }
  }

  return chokudaiData[D].max_element();
}

signed main() {

  int D;
  cin >> D;

  vector<int> c(TYPES + 1, 0);
  vector<vector<int>> s(D + 1, vector<int>(TYPES + 1, 0));

  REPS(i, TYPES) { cin >> c[i]; }

  REPS(i, D) {
    REPS(j, TYPES) { cin >> s[i][j]; }
  }

  // Dにちめまで chokudai サーチをする
  auto res = ChokudaiSearch(D, c, s);

  REPS(i, D) { cout << (int)res.contests[i] << "\\n"; }

  return 0;
}