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

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, i##_len = int(n); i < i##_len; ++i)
#define rep(i, a, b) for (int i = int(a); i < int(b); ++i)
#define All(x) (x).begin(), (x).end()
#define rAll(x) (x).rbegin(), (x).rend()
using namespace std;
using ll = long long;

int main() {
  // 方針
  // 毎日満足度は低下し続ける
  // 満足度上昇の方法はコンテスト開催のみ
  // 開催されてないコンテストを放置すると低下が著しくなる
  // 実際にコンテストを開いた時の満足度上昇が最大のものを採用してみる
  // 低下をなくせる分を上昇と捉えると、c_i(d-last(d,i)) + s_{d,i}
  // だけペイすると考えられる？→あんまり適当じゃない
  // r日ずつ全探索を[D/r+1]回繰り返す
  // 探索パターン数は26^rで、シミュレーションには26r回かかる、これを[D/r+1]回繰り返すので
  // 計算量はO(D26^{r+1})
  // r = 3が限界
  int D;
  cin >> D;
  int c[26], last[26] = {}, s[365][26], lastcpy[26];
  REP(i, 26) cin >> c[i];
  REP(i, D) REP(j, 26) cin >> s[i][j];
  constexpr int r = 6; // 何日に分けて全探索を行うか
  constexpr int num =
      6; // 1日毎にいくつ全探索するか:cを降順ソートして前半num個だけを選び続ける貪欲
  int all = 1;
  REP(i, r) all *= num;
  int up, ptncpy;
  int res[r], calcres[r], reslast[26];
  int ord[26];
  iota(ord, ord + 26, 0);
  stable_sort(ord, ord + 26, [&](int x, int y) { return c[x] > c[y]; });
  stable_sort(c, c + 26, [](int x, int y) { return x > y; });
  for (int i = 0; i < D; i += r) {
    int tmp = -1e9;
    for (int pattern = 0; pattern < all;
         pattern++) { // r日でそれぞれ何処を選ぶか全探索
      up = 0;
      ptncpy = pattern;
      memcpy(lastcpy, last,
             sizeof(int) * 26); // lastを更新しなければならないのでコピーを取る
      REP(j, r) { // r日探索
        if (i + j >= D)
          break;
        calcres[j] = ptncpy % num;
        REP(k,
            26) { // スコアに影響のある26パターンについて処理しなければならない
          if (calcres[j] ==
              k) { // 選ぶパターンのときはlastを更新してスコアを加算
            last[k] = i + j;
            up += s[i + j][k];
          } else
            up -= c[k] * (i + j - last[k]); // そうでないときはlastを参照して減算
        }
        ptncpy /= num; // これをi+r-1日目まで繰り返して終了
      }

      if (tmp < up) { // もしスコアが高くなるならば結果を更新する
        tmp = up;
        memcpy(res, calcres, sizeof(int) * r); //
        memcpy(reslast, last, sizeof(int) * 26);
      }
      memcpy(last, lastcpy, sizeof(int) * 26);
    }
    memcpy(last, reslast, sizeof(int) * 26);
    REP(j, r) if (i + j < D) { cout << ord[res[j]] + 1 << endl; }
  }
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, i##_len = int(n); i < i##_len; ++i)
#define rep(i, a, b) for (int i = int(a); i < int(b); ++i)
#define All(x) (x).begin(), (x).end()
#define rAll(x) (x).rbegin(), (x).rend()
using namespace std;
using ll = long long;

int main() {
  // 方針
  // 毎日満足度は低下し続ける
  // 満足度上昇の方法はコンテスト開催のみ
  // 開催されてないコンテストを放置すると低下が著しくなる
  // 実際にコンテストを開いた時の満足度上昇が最大のものを採用してみる
  // 低下をなくせる分を上昇と捉えると、c_i(d-last(d,i)) + s_{d,i}
  // だけペイすると考えられる？→あんまり適当じゃない
  // r日ずつ全探索を[D/r+1]回繰り返す
  // 探索パターン数は26^rで、シミュレーションには26r回かかる、これを[D/r+1]回繰り返すので
  // 計算量はO(D26^{r+1})
  // r = 3が限界
  int D;
  cin >> D;
  int c[26], last[26] = {}, s[365][26], lastcpy[26];
  REP(i, 26) cin >> c[i];
  REP(i, D) REP(j, 26) cin >> s[i][j];
  constexpr int r = 8;   // 何日に分けて全探索を行うか
  constexpr int num = 6; // 1日毎にいくつ全探索するか
  int all = 1;
  REP(i, r) all *= num;
  int up, ptncpy;
  int res[r], calcres[r], reslast[26];
  int ord[26];
  iota(ord, ord + 26, 0);
  stable_sort(ord, ord + 26, [&](int x, int y) { return c[x] > c[y]; });
  stable_sort(c, c + 26, [](int x, int y) { return x > y; });
  for (int i = 0; i < D; i += r) {
    int tmp = -1e9;
    for (int pattern = 0; pattern < all;
         pattern++) { // r日でそれぞれ何処を選ぶか全探索
      up = 0;
      ptncpy = pattern;
      memcpy(lastcpy, last,
             sizeof(int) * 26); // lastを更新しなければならないのでコピーを取る
      REP(j, r) { // r日探索
        if (i + j >= D)
          break;
        calcres[j] = ptncpy % num;
        REP(k,
            26) { // スコアに影響のある26パターンについて処理しなければならない
          if (calcres[j] ==
              k) { // 選ぶパターンのときはlastを更新してスコアを加算
            last[k] = i + j;
            up += s[i + j][k];
          } else
            up -= c[k] * (i + j - last[k]); // そうでないときはlastを参照して減算
        }
        ptncpy /= num; // これをi+r-1日目まで繰り返して終了
      }

      if (tmp < up) { // もしスコアが高くなるならば結果を更新する
        tmp = up;
        memcpy(res, calcres, sizeof(int) * r); //
        memcpy(reslast, last, sizeof(int) * 26);
      }
      memcpy(last, lastcpy, sizeof(int) * 26);
    }
    memcpy(last, reslast, sizeof(int) * 26);
    REP(j, r) if (i + j < D) { cout << ord[res[j]] + 1 << endl; }
  }
}