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;
}

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

  int score() const { return score_; }
  void update(int p, int v) {}

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> 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;
  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;
      int updated_score = emulate(current);

      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 {
        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.9999;
  int greedy_mode = 2;
  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;
  }
  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;

class SingleClass {
public:
  SingleClass(int d) {}

private:
  vector<int> prev_, next_;
};

/*
class ScoreManager {
public:
        ScoreManager(const vector<int>& ans);

        int score() const { return score_; }
        void update(int p, int v) {

        }

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

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;
}

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> 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;
  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;
      int updated_score = emulate(current);

      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;
      } else {
        current[t] = current_v;
      }
    }
    temp *= temp_decay;

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

int main(int argc, char **argv) {
  double temp = 2000;
  double temp_decay = 0.9999;
  int greedy_mode = 2;
  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;
  }
  for (int i = 0; i < D; ++i)
    printf("%d\\n", ans[i] + 1);
  fprintf(stderr, "score: %d\\n", emulate(ans));
  return 0;
}