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

#include <algorithm>
#include <array>
#include <chrono>
#include <iostream>
#include <set>
#include <vector>

int const INF = 1e9;

uint64_t xor64(void) {
  static uint64_t x = 88172645463325252ULL;
  x = x ^ (x << 7);
  return x = x ^ (x >> 9);
}

auto b_cl = std::chrono::system_clock::now();
inline double get_time() {
  auto e_cl = std::chrono::system_clock::now();
  double msec =
      std::chrono::duration_cast<std::chrono::milliseconds>(e_cl - b_cl)
          .count();
  return msec;
}

struct state {
  int score_k;
  int type;
  int last[26];
  int score;
  std::vector<state>::iterator prev;
  bool operator<(state const &rhs) const {
    return score_k > rhs.score_k;
  } // reverse order
};

int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  int D;
  std::cin >> D;
  int c[26];
  for (auto &ci : c)
    std::cin >> ci;
  std::vector<std::array<int, 26>> s(D);
  for (int d = 0; d < D; ++d) {
    for (auto &si : s[d])
      std::cin >> si;
  }
  int const B = 840;
  int const K = 2;
  std::vector<int> t(D);

  std::vector<std::vector<state>> states(D + 1);
  auto beam_step = [&](int d, int k) {
    auto &prev = states[d];
    auto &curr = states[d + 1];
    curr.reserve(prev.size() * 26);
    int dd = std::min(d + k, D - 1);
    for (auto it = prev.begin(); it != prev.end(); ++it) {
      for (int T = 0; T < 26; ++T) {
        curr.push_back(*it);
        state &st = curr.back();
        st.prev = it;
        st.last[T] = d;
        st.type = T;
        st.score_k = st.score + s[d][T];
        for (int cx = 0; cx < 26; ++cx) {
          st.score_k -= c[cx] * (d + dd - 2 * st.last[cx]) * (dd - d + 1) / 2;
        }
      }
    }
    std::sort(curr.begin(), curr.end());
    if (curr.size() > B)
      curr.resize(B);
    for (auto &st : curr) {
      st.score += s[d][st.type];
      for (int cx = 0; cx < 26; ++cx) {
        st.score -= c[cx] * (d - st.last[cx]);
      }
    }
  };

  auto beam_search = [&](int k) {
    states.assign(D + 1, std::vector<state>());
    states[0].emplace_back();
    states[0][0].score = 0;
    states[0][0].score_k = 0;
    std::fill_n(states[0][0].last, 26, -1);
    for (int d = 0; d < D; ++d)
      beam_step(d, k);
    auto it = states[D].begin();
    for (int d = D - 1; d >= 0; it = it->prev, --d) {
      t[d] = it->type;
    }
  };
  beam_search(K);

  std::set<int> last[26];
  for (auto &li : last)
    li.insert(-1); // sentinel
  for (int d = 0; d < D; ++d)
    last[t[d]].insert(d);
  for (auto &li : last)
    li.insert(D); // sentinel

  // hill climbing
  auto sum_up = [](int d) { return d * (d - 1) / 2; };
  auto score = [&](int d, int i) -> int {
    int res = s[d][i];
    auto it = last[i].lower_bound(d);
    int nd = *it;
    int pd = *--it;
    int diff = sum_up(d - pd) + sum_up(nd - d) - sum_up(nd - pd);
    res -= c[i] * diff;
    return res;
  };
  int lm = 0, renew = 0;
  int sc[26];
  auto one_day = [&](int d) {
    int pi = t[d];
    last[pi].erase(d);
    for (int i = 0; i < 26; ++i)
      sc[i] = score(d, i);
    int mi = std::max_element(sc, sc + 26) - sc;
    if (mi != pi) {
      t[d] = mi;
      // ans += sc[mi] - sc[pi];
      ++renew;
    }
    last[mi].insert(d);
  };

  // hill climbing
  int range = 25;
  for (int rep = 0;; ++rep) {
    if ((xor64() >> 25) % 2) {
      one_day(xor64() % 365);
    } else {
      // swap
      int d1 = xor64() % D, d2 = xor64() % D;
      while (d1 < d2 - range || d2 < d1 - range || t[d1] == t[d2]) {
        d1 = xor64() % D;
        d2 = xor64() % D;
      }
      int pi1 = t[d1], pi2 = t[d2];
      last[pi1].erase(d1);
      int diff = score(d1, pi2) - score(d1, pi1);
      last[pi2].insert(d1);
      last[pi2].erase(d2);
      diff += score(d2, pi1) - score(d2, pi2);
      if (diff > 0) {
        last[pi1].insert(d2);
        t[d1] = pi2;
        t[d2] = pi1;
        lm = 0;
      } else {
        last[pi2].insert(d2);
        last[pi2].erase(d1);
        last[pi1].insert(d1);
      }
    }
    if (rep % 100 == 0) {
      int x = get_time();
      if (x > 1640)
        range = 20;
      if (x > 1780)
        range = 15;
      if (x > 1920)
        range = 10;
      if (x > 1950)
        break;
    }
  }
  for (auto ti : t)
    std::cout << ti + 1 << "\\n";
  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <array>
#include <chrono>
#include <iostream>
#include <set>
#include <vector>

int const INF = 1e9;

uint64_t xor64(void) {
  static uint64_t x = 88172645463325252ULL;
  x = x ^ (x << 7);
  return x = x ^ (x >> 9);
}

auto b_cl = std::chrono::system_clock::now();
inline double get_time() {
  auto e_cl = std::chrono::system_clock::now();
  double msec =
      std::chrono::duration_cast<std::chrono::milliseconds>(e_cl - b_cl)
          .count();
  return msec;
}

struct state {
  int score_k;
  int type;
  int last[26];
  int score;
  std::vector<state>::iterator prev;
  bool operator<(state const &rhs) const {
    return score_k > rhs.score_k;
  } // reverse order
};

int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  int D;
  std::cin >> D;
  int c[26];
  for (auto &ci : c)
    std::cin >> ci;
  std::vector<std::array<int, 26>> s(D);
  for (int d = 0; d < D; ++d) {
    for (auto &si : s[d])
      std::cin >> si;
  }
  int const B = 840;
  int const K = 2;
  std::vector<int> t(D);

  std::vector<std::vector<state>> states(D + 1);
  auto beam_step = [&](int d, int k) {
    auto &prev = states[d];
    auto &curr = states[d + 1];
    curr.reserve(prev.size() * 26);
    int dd = std::min(d + k, D - 1);
    for (auto it = prev.begin(); it != prev.end(); ++it) {
      for (int T = 0; T < 26; ++T) {
        curr.push_back(*it);
        state &st = curr.back();
        st.prev = it;
        st.last[T] = d;
        st.type = T;
        st.score_k = st.score + s[d][T];
        for (int cx = 0; cx < 26; ++cx) {
          st.score_k -= c[cx] * (d + dd - 2 * st.last[cx]) * (dd - d + 1) / 2;
        }
      }
    }
    std::sort(curr.begin(), curr.end());
    if (curr.size() > B)
      curr.resize(B);
    for (auto &st : curr) {
      st.score += s[d][st.type];
      for (int cx = 0; cx < 26; ++cx) {
        st.score -= c[cx] * (d - st.last[cx]);
      }
    }
  };

  auto beam_search = [&](int k) {
    states.assign(D + 1, std::vector<state>());
    states[0].emplace_back();
    states[0][0].score = 0;
    states[0][0].score_k = 0;
    std::fill_n(states[0][0].last, 26, -1);
    for (int d = 0; d < D; ++d)
      beam_step(d, k);
    auto it = states[D].begin();
    for (int d = D - 1; d >= 0; it = it->prev, --d) {
      t[d] = it->type;
    }
  };
  beam_search(K);

  std::set<int> last[26];
  for (auto &li : last)
    li.insert(-1); // sentinel
  for (int d = 0; d < D; ++d)
    last[t[d]].insert(d);
  for (auto &li : last)
    li.insert(D); // sentinel

  // hill climbing
  auto sum_up = [](int d) { return d * (d - 1) / 2; };
  auto score = [&](int d, int i) -> int {
    int res = s[d][i];
    auto it = last[i].lower_bound(d);
    int nd = *it;
    int pd = *--it;
    int diff = sum_up(d - pd) + sum_up(nd - d) - sum_up(nd - pd);
    res -= c[i] * diff;
    return res;
  };
  int lm = 0, renew = 0;
  int sc[26];
  auto one_day = [&](int d) {
    int pi = t[d];
    last[pi].erase(d);
    for (int i = 0; i < 26; ++i)
      sc[i] = score(d, i);
    int mi = std::max_element(sc, sc + 26) - sc;
    if (mi != pi) {
      t[d] = mi;
      // ans += sc[mi] - sc[pi];
      ++renew;
    }
    last[mi].insert(d);
  };

  // hill climbing
  int range = 25;
  for (int rep = 0;; ++rep) {
    if ((xor64() >> 25) % 2) {
      one_day(xor64() % 365);
    } else {
      // swap
      int d1 = xor64() % D, d2 = xor64() % D;
      while (d1 < d2 - range || d2 < d1 - range || t[d1] == t[d2]) {
        d1 = xor64() % D;
        d2 = xor64() % D;
      }
      int pi1 = t[d1], pi2 = t[d2];
      last[pi1].erase(d1);
      int diff = score(d1, pi2) - score(d1, pi1);
      last[pi2].insert(d1);
      last[pi2].erase(d2);
      diff += score(d2, pi1) - score(d2, pi2);
      if (diff > 0) {
        last[pi1].insert(d2);
        t[d1] = pi2;
        t[d2] = pi1;
        lm = 0;
      } else {
        last[pi2].insert(d2);
        last[pi2].erase(d1);
        last[pi1].insert(d1);
      }
    }
    if (rep % 100 == 0) {
      int x = get_time();
      if (x > 1650)
        range = 20;
      if (x > 1800)
        range = 15;
      if (x > 1950)
        range = 10;
      if (x > 1980)
        break;
    }
  }
  for (auto ti : t)
    std::cout << ti + 1 << "\\n";
  return 0;
}