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

#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <vector>

using namespace std;
#define MOD @
#define ADD(X, Y) ((X) = ((X) + (Y) % MOD) % MOD)
typedef long long i64;
typedef vector<int> ivec;
typedef vector<string> svec;

const int nKind = 26;
const int actualD = 365;
mt19937 rnd(12345);

int D;
int C[nKind], S[actualD][nKind];

int urand(int lo, int hi) { return uniform_int_distribution<int>(lo, hi)(rnd); }

int emulate_slow(const vector<int> &ans) {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;
  int score = 0;
  for (int i = 0; i < D; ++i) {
    score += S[i][ans[i]];
    last[ans[i]] = i;
    for (int j = 0; j < nKind; ++j) {
      score -= C[j] * (i - last[j]);
    }
  }
  return score;
}

int emulate(const vector<int> &ans) {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;
  int score = 0;
  for (int i = 0; i < D; ++i) {
    score += S[i][ans[i]];

    int elapsed = i - last[ans[i]];
    score -= elapsed * (elapsed - 1) / 2 * C[ans[i]];
    last[ans[i]] = i;
  }
  for (int j = 0; j < nKind; ++j) {
    int elapsed = D - last[j];
    score -= elapsed * (elapsed - 1) / 2 * C[j];
  }
  return score;
}

inline int tri(int x) { return x * (x - 1) / 2; }

class ScoreManager {
public:
  ScoreManager(const vector<int> &ans) : ans_(ans), score_(emulate(ans)) {}

  int score() const { return score_; }
  int find_prev(int p, int v) {
    while (p >= 0) {
      if (ans_[p] == v)
        return p;
      --p;
    }
    return -1;
  }
  int find_next(int p, int v) {
    while (p < ans_.size()) {
      if (ans_[p] == v)
        return p;
      ++p;
    }
    return ans_.size();
  }
  void update(int p, int v) {
    score_ -= S[p][ans_[p]];
    score_ += S[p][v];

    {
      int x = ans_[p];
      int pre = find_prev(p - 1, x);
      int nxt = find_next(p + 1, x);
      score_ += C[x] * (tri(p - pre) + tri(nxt - p) - tri(nxt - pre));
    }
    {
      int pre = find_prev(p - 1, v);
      int nxt = find_next(p + 1, v);
      score_ -= C[v] * (tri(p - pre) + tri(nxt - p) - tri(nxt - pre));
    }
    ans_[p] = v;
  }
  void update_force(int p, int v, int score) {
    ans_[p] = v;
    score_ = score;
  }

private:
  vector<int> ans_;
  int score_;
};

vector<int> greedy() {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;

  vector<int> ans;
  for (int i = 0; i < D; ++i) {
    int profit[nKind];
    for (int j = 0; j < nKind; ++j) {
      profit[j] = C[j] * (i - last[j]) + S[i][j];
    }
    int best = 0;
    for (int j = 0; j < nKind; ++j) {
      if (profit[best] < profit[j])
        best = j;
    }
    last[best] = i;
    ans.push_back(best);
  }
  return ans;
}

vector<int> greedy2() {
  vector<int> ans;
  for (int i = 0; i < D; ++i) {
    int profit[nKind];
    for (int j = 0; j < nKind; ++j) {
      profit[j] = S[i][j];
    }
    int best = 0;
    for (int j = 0; j < nKind; ++j) {
      if (profit[best] < profit[j])
        best = j;
    }
    ans.push_back(best);
  }
  return ans;
}

vector<int> greedy3() {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;

  vector<int> ans;
  for (int i = 0; i < D; ++i) {
    double profit[nKind];
    for (int j = 0; j < nKind; ++j) {
      profit[j] = C[j] * (i - last[j]) * 1.0 + S[i][j] * 0.5;
    }
    int best = 0;
    for (int j = 0; j < nKind; ++j) {
      if (profit[best] < profit[j])
        best = j;
    }
    last[best] = i;
    ans.push_back(best);
  }
  return ans;
}

vector<int> SA(vector<int> initial, double initial_temp, double temp_decay,
               double timeout) {
  uniform_real_distribution<double> ureal(0.0, 1.0);

  auto start = chrono::system_clock::now();
  vector<int> best = initial;
  int best_score = emulate(best);

  vector<int> current = initial;
  int current_score = best_score;

  int step = 0;
  double temp = initial_temp;
  int best_step = 0;

  int n_sadparrot = 0;

  ScoreManager manager(current);
  for (;;) {
    bool upd = false;
    for (int i = 0; i < 100; ++i) {
      int t = urand(0, D - 1);
      int v = urand(0, nKind - 1);

      int current_v = current[t];
      if (v == current_v)
        continue;

      current[t] = v;
      manager.update(t, v);
      int updated_score = manager.score(); // emulate(current);
      /*
      if (updated_score != manager.score()) {
              fprintf(stderr, "%d %d\\n", updated_score, manager.score());
              abort();
      }
      */

      bool updated = false;

      if (current_score < updated_score ||
          ureal(rnd) < exp((updated_score - current_score) / temp)) {
        updated = true;
      }

      if (updated) {
        current_score = updated_score;
        if (best_score < updated_score) {
          best = current;
          best_step = step;
        }
        upd = true;
      } else {
        // manager.update(t, current_v);
        manager.update_force(t, current_v, current_score);
        current[t] = current_v;
      }
    }
    temp *= temp_decay;
    if (!upd)
      ++n_sadparrot;
    double elapsed = chrono::duration_cast<chrono::nanoseconds>(
                         chrono::system_clock::now() - start)
                         .count() /
                     1e9;
    if (elapsed > timeout)
      break;
    ++step;
  }
  fprintf(stderr, "step: %d/%d (%d)\\n", best_step, step, n_sadparrot);
  return best;
}

int main(int argc, char **argv) {
  double temp = 2000;
  double temp_decay = 0.99995;
  int greedy_mode = 100;
  if (argc >= 2) {
    temp = atof(argv[1]);
    temp_decay = atof(argv[2]);
    greedy_mode = atoi(argv[3]);
  }
  scanf("%d", &D);
  for (int i = 0; i < nKind; ++i)
    scanf("%d", C + i);
  for (int i = 0; i < D; ++i) {
    for (int j = 0; j < nKind; ++j)
      scanf("%d", &(S[i][j]));
  }
  vector<int> ans;
  if (greedy_mode == 0) {
    ans = greedy();
    ans = SA(ans, temp, temp_decay, 1.9);
  } else if (greedy_mode == 1) {
    ans = greedy2();
    ans = SA(ans, temp, temp_decay, 1.9);
  } else if (greedy_mode == 2) {
    vector<int> ans1 = greedy();
    ans1 = SA(ans1, temp, temp_decay, 0.95);
    vector<int> ans2 = greedy2();
    ans2 = SA(ans2, temp, temp_decay, 0.95);

    if (emulate(ans1) < emulate(ans2))
      ans = ans2;
    else
      ans = ans1;
  } else if (greedy_mode == 3) {
    ans = greedy3();
    ans = SA(ans, temp, temp_decay, 1.9);
  } else if (greedy_mode >= 10 && greedy_mode < 40) {
    int rep = greedy_mode - 10;

    int score = -2100000000;
    for (int i = 0; i < rep; ++i) {
      vector<int> initial_ans;
      if (i % 3 == 0)
        initial_ans = greedy();
      else if (i % 3 == 1)
        initial_ans = greedy2();
      else if (i % 3 == 2)
        initial_ans = greedy3();
      vector<int> ans_cand = SA(initial_ans, temp, temp_decay, 1.9 / rep);

      int score_cand = emulate(ans_cand);
      if (score < score_cand) {
        ans = ans_cand;
        score = score_cand;
      }
    }
  } else if (greedy_mode >= 40 && greedy_mode < 100) {
    int rep = greedy_mode - 40;

    int score = -2100000000;
    for (int i = 0; i < rep; ++i) {
      vector<int> initial_ans;
      if (i == 0)
        initial_ans = greedy3();
      else
        initial_ans = ans;
      vector<int> ans_cand = SA(initial_ans, temp, temp_decay, 1.9 / rep);

      int score_cand = emulate(ans_cand);
      if (score < score_cand) {
        ans = ans_cand;
        score = score_cand;
      }
    }
  } else if (greedy_mode == 100) {
    int score = -2100000000;
    int rep = 4;

    double cost[] = {0.45, 0.45, 0.45, 0.45};
    for (int i = 0; i < rep; ++i) {
      vector<int> initial_ans;
      if (i == 0)
        initial_ans = greedy3();
      else
        initial_ans = ans;
      vector<int> ans_cand =
          SA(initial_ans, temp, temp_decay * (cost[0] / cost[i]), cost[i]);

      int score_cand = emulate(ans_cand);
      if (score < score_cand) {
        ans = ans_cand;
        score = score_cand;
      }
    }
  }
  for (int i = 0; i < D; ++i)
    printf("%d\\n", ans[i] + 1);
  fprintf(stderr, "score: %d\\n", emulate(ans));
  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <vector>

using namespace std;
#define MOD @
#define ADD(X, Y) ((X) = ((X) + (Y) % MOD) % MOD)
typedef long long i64;
typedef vector<int> ivec;
typedef vector<string> svec;

const int nKind = 26;
const int actualD = 365;
mt19937 rnd(12345);

int D;
int C[nKind], S[actualD][nKind];

int urand(int lo, int hi) { return uniform_int_distribution<int>(lo, hi)(rnd); }

int emulate_slow(const vector<int> &ans) {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;
  int score = 0;
  for (int i = 0; i < D; ++i) {
    score += S[i][ans[i]];
    last[ans[i]] = i;
    for (int j = 0; j < nKind; ++j) {
      score -= C[j] * (i - last[j]);
    }
  }
  return score;
}

int emulate(const vector<int> &ans) {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;
  int score = 0;
  for (int i = 0; i < D; ++i) {
    score += S[i][ans[i]];

    int elapsed = i - last[ans[i]];
    score -= elapsed * (elapsed - 1) / 2 * C[ans[i]];
    last[ans[i]] = i;
  }
  for (int j = 0; j < nKind; ++j) {
    int elapsed = D - last[j];
    score -= elapsed * (elapsed - 1) / 2 * C[j];
  }
  return score;
}

inline int tri(int x) { return x * (x - 1) / 2; }

class ScoreManager {
public:
  ScoreManager(const vector<int> &ans) : ans_(ans), score_(emulate(ans)) {}

  int score() const { return score_; }
  int find_prev(int p, int v) {
    while (p >= 0) {
      if (ans_[p] == v)
        return p;
      --p;
    }
    return -1;
  }
  int find_next(int p, int v) {
    while (p < ans_.size()) {
      if (ans_[p] == v)
        return p;
      ++p;
    }
    return ans_.size();
  }
  void update(int p, int v) {
    score_ -= S[p][ans_[p]];
    score_ += S[p][v];

    {
      int x = ans_[p];
      int pre = find_prev(p - 1, x);
      int nxt = find_next(p + 1, x);
      score_ += C[x] * (tri(p - pre) + tri(nxt - p) - tri(nxt - pre));
    }
    {
      int pre = find_prev(p - 1, v);
      int nxt = find_next(p + 1, v);
      score_ -= C[v] * (tri(p - pre) + tri(nxt - p) - tri(nxt - pre));
    }
    ans_[p] = v;
  }
  void update_force(int p, int v, int score) {
    ans_[p] = v;
    score_ = score;
  }

private:
  vector<int> ans_;
  int score_;
};

vector<int> greedy() {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;

  vector<int> ans;
  for (int i = 0; i < D; ++i) {
    int profit[nKind];
    for (int j = 0; j < nKind; ++j) {
      profit[j] = C[j] * (i - last[j]) + S[i][j];
    }
    int best = 0;
    for (int j = 0; j < nKind; ++j) {
      if (profit[best] < profit[j])
        best = j;
    }
    last[best] = i;
    ans.push_back(best);
  }
  return ans;
}

vector<int> greedy2() {
  vector<int> ans;
  for (int i = 0; i < D; ++i) {
    int profit[nKind];
    for (int j = 0; j < nKind; ++j) {
      profit[j] = S[i][j];
    }
    int best = 0;
    for (int j = 0; j < nKind; ++j) {
      if (profit[best] < profit[j])
        best = j;
    }
    ans.push_back(best);
  }
  return ans;
}

vector<int> greedy3() {
  int last[nKind];
  for (int i = 0; i < nKind; ++i)
    last[i] = -1;

  vector<int> ans;
  for (int i = 0; i < D; ++i) {
    double profit[nKind];
    for (int j = 0; j < nKind; ++j) {
      profit[j] = C[j] * (i - last[j]) * 1.0 + S[i][j] * 0.5;
    }
    int best = 0;
    for (int j = 0; j < nKind; ++j) {
      if (profit[best] < profit[j])
        best = j;
    }
    last[best] = i;
    ans.push_back(best);
  }
  return ans;
}

vector<int> SA(vector<int> initial, double initial_temp, double temp_decay,
               double timeout) {
  uniform_real_distribution<double> ureal(0.0, 1.0);

  auto start = chrono::system_clock::now();
  vector<int> best = initial;
  int best_score = emulate(best);

  vector<int> current = initial;
  int current_score = best_score;

  int step = 0;
  double temp = initial_temp;
  int best_step = 0;

  ScoreManager manager(current);
  for (;;) {
    for (int i = 0; i < 100; ++i) {
      int t = urand(0, D - 1);
      int v = urand(0, nKind - 1);

      int current_v = current[t];
      if (v == current_v)
        continue;

      current[t] = v;
      manager.update(t, v);
      int updated_score = manager.score(); // emulate(current);
      /*
      if (updated_score != manager.score()) {
              fprintf(stderr, "%d %d\\n", updated_score, manager.score());
              abort();
      }
      */

      bool updated = false;

      if (current_score < updated_score ||
          ureal(rnd) < exp((updated_score - current_score) / temp)) {
        updated = true;
      }

      if (updated) {
        current_score = updated_score;
        if (best_score < updated_score) {
          best = current;
          best_step = step;
        }
      } else {
        // manager.update(t, current_v);
        manager.update_force(t, current_v, current_score);
        current[t] = current_v;
      }
    }
    temp *= temp_decay;

    double elapsed = chrono::duration_cast<chrono::nanoseconds>(
                         chrono::system_clock::now() - start)
                         .count() /
                     1e9;
    if (elapsed > timeout)
      break;
    ++step;
  }
  fprintf(stderr, "step: %d/%d\\n", best_step, step);
  return best;
}

int main(int argc, char **argv) {
  double temp = 2000;
  double temp_decay = 0.99995;
  int greedy_mode = 100;
  if (argc >= 2) {
    temp = atof(argv[1]);
    temp_decay = atof(argv[2]);
    greedy_mode = atoi(argv[3]);
  }
  scanf("%d", &D);
  for (int i = 0; i < nKind; ++i)
    scanf("%d", C + i);
  for (int i = 0; i < D; ++i) {
    for (int j = 0; j < nKind; ++j)
      scanf("%d", &(S[i][j]));
  }
  vector<int> ans;
  if (greedy_mode == 0) {
    ans = greedy();
    ans = SA(ans, temp, temp_decay, 1.9);
  } else if (greedy_mode == 1) {
    ans = greedy2();
    ans = SA(ans, temp, temp_decay, 1.9);
  } else if (greedy_mode == 2) {
    vector<int> ans1 = greedy();
    ans1 = SA(ans1, temp, temp_decay, 0.95);
    vector<int> ans2 = greedy2();
    ans2 = SA(ans2, temp, temp_decay, 0.95);

    if (emulate(ans1) < emulate(ans2))
      ans = ans2;
    else
      ans = ans1;
  } else if (greedy_mode == 3) {
    ans = greedy3();
    ans = SA(ans, temp, temp_decay, 1.9);
  } else if (greedy_mode >= 10 && greedy_mode < 40) {
    int rep = greedy_mode - 10;

    int score = -2100000000;
    for (int i = 0; i < rep; ++i) {
      vector<int> initial_ans;
      if (i % 3 == 0)
        initial_ans = greedy();
      else if (i % 3 == 1)
        initial_ans = greedy2();
      else if (i % 3 == 2)
        initial_ans = greedy3();
      vector<int> ans_cand = SA(initial_ans, temp, temp_decay, 1.9 / rep);

      int score_cand = emulate(ans_cand);
      if (score < score_cand) {
        ans = ans_cand;
        score = score_cand;
      }
    }
  } else if (greedy_mode >= 40 && greedy_mode < 100) {
    int rep = greedy_mode - 40;

    int score = -2100000000;
    for (int i = 0; i < rep; ++i) {
      vector<int> initial_ans;
      if (i == 0)
        initial_ans = greedy3();
      else
        initial_ans = ans;
      vector<int> ans_cand = SA(initial_ans, temp, temp_decay, 1.9 / rep);

      int score_cand = emulate(ans_cand);
      if (score < score_cand) {
        ans = ans_cand;
        score = score_cand;
      }
    }
  } else if (greedy_mode == 100) {
    int score = -2100000000;
    int rep = 4;

    double cost[] = {0.5, 0.5, 0.5, 0.5};
    for (int i = 0; i < rep; ++i) {
      vector<int> initial_ans;
      if (i == 0)
        initial_ans = greedy3();
      else
        initial_ans = ans;
      vector<int> ans_cand =
          SA(initial_ans, temp, temp_decay * (cost[0] / cost[i]), cost[i]);

      int score_cand = emulate(ans_cand);
      if (score < score_cand) {
        ans = ans_cand;
        score = score_cand;
      }
    }
  }
  for (int i = 0; i < D; ++i)
    printf("%d\\n", ans[i] + 1);
  fprintf(stderr, "score: %d\\n", emulate(ans));
  return 0;
}