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

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;

typedef long double real;

const int MAX_M = 2000;
const int MAX_N = 2000;

const real EPS = 1e-8;

bool EQ(real a, real b) { return abs(a - b) < EPS; }

real P1[MAX_M + 1]
       [MAX_M +
        1]; // P1[m][x] ::
            // アイドル2,3,...,Nがビジュアルアピールをm回中x回だけ行う確率
real SP[MAX_M + 1]
       [MAX_M +
        1]; // SP[m][x] ::
            // アイドル2,3,...,Nがビジュアルアピールをm回中x回以上行う確率

int N, M;
vector<int> vi, da, vo;

void initP1() {
  for (int m = 0; m <= MAX_M; m++)
    for (int x = 0; x <= MAX_M; x++)
      P1[m][x] = 0;
  P1[0][0] = 1;
  for (int m = 1; m <= MAX_M; m++) {
    for (int x = 0; x <= m; x++) {
      P1[m][x] += P1[m - 1][x] * (2.0 / 3.0);
      if (x >= 1) {
        P1[m][x] += P1[m - 1][x - 1] * (1.0 / 3.0);
      }
    }
  }
}

void initSP() {
  for (int m = 0; m <= MAX_M; m++)
    for (int x = 0; x <= MAX_M; x++)
      SP[m][x] = 0;
  for (int m = 0; m <= MAX_M; m++) {
    SP[m][0] = 1;
    for (int x = 1; x <= m; x++) {
      SP[m][x] = SP[m][x - 1] - P1[m][x - 1];
    }
    assert(EQ(SP[m][m], P1[m][m]));
  }
}

void dump() {
  printf("SP:\\n");
  for (int i = 0; i <= M; i++) {
    for (int j = 0; j <= i; j++) {
      printf("%3.3Lf ", SP[i][j]);
    }
    printf("\\n");
  }
}

const real INF = 1e8;

real memo[MAX_M + 1][6];
real top(int x, int p, const vector<int> &V) {
  static real dp[MAX_N + 1][5];
  if (memo[x][p] > -INF)
    return memo[x][p];
  int k = V[1];
  int P = x * k;
  for (int i = 0; i <= N; i++)
    for (int j = 0; j <= 4; j++)
      dp[i][j] = 0;
  dp[1][1] = 1.0;
  dp[1][4] = 1.0;
  for (int i = 2; i <= N; i++) {
    real X;
    if ((P + V[i] - 1) / V[i] > M) {
      X = 0;
    } else {
      X = SP[M][(P + V[i] - 1) / V[i]];
    }
    assert(X >= 0);
    assert(X <= 1);
    dp[i][1] = dp[i - 1][1] * (1.0 - X);
    dp[i][2] = dp[i - 1][2] * (1.0 - X) + dp[i - 1][1] * X;
    dp[i][3] = dp[i - 1][3] * (1.0 - X) + dp[i - 1][2] * X;

    dp[i][4] = dp[i - 1][4] * X;
  }
  return memo[x][p] = (dp[N][1] + dp[N][2] + dp[N][3]) * p - dp[N][4] * 1;
}

void solve() {
  real ans = -INF;
  for (int i = 0; i <= M; i++)
    for (int j = 0; j < 6; j++)
      memo[i][j] = -INF;
  for (int x = 0; x <= M; x++) {
    for (int y = 0; y <= M - x; y++) {
      int z = M - (x + y);
      assert(z >= 0);
      // viをx, daをy, voをz回行う
      ans = max(ans, top(x, 5, vi) + top(y, 3, da) + top(z, 2, vo));
    }
  }
  printf("%.18Lf\\n", ans);
}

int main() {
  cin >> N >> M;
  vi.clear();
  da.clear();
  vo.clear();
  vi.resize(N + 1);
  da.resize(N + 1);
  vo.resize(N + 1);
  for (int i = 1; i <= N; i++)
    cin >> vi[i] >> da[i] >> vo[i];
  initP1();
  initSP();
  solve();
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;

const int MAX_M = 2000;
const int MAX_N = 2000;

const double EPS = 1e-8;

bool EQ(double a, double b) { return abs(a - b) < EPS; }

double P1[MAX_M + 1]
         [MAX_M +
          1]; // P1[m][x] ::
              // アイドル2,3,...,Nがビジュアルアピールをm回中x回だけ行う確率
double SP[MAX_M + 1]
         [MAX_M +
          1]; // SP[m][x] ::
              // アイドル2,3,...,Nがビジュアルアピールをm回中x回以上行う確率

int N, M;
vector<int> vi, da, vo;

void initP1() {
  for (int m = 0; m <= MAX_M; m++)
    for (int x = 0; x <= MAX_M; x++)
      P1[m][x] = 0;
  P1[0][0] = 1;
  for (int m = 1; m <= MAX_M; m++) {
    for (int x = 0; x <= m; x++) {
      P1[m][x] += P1[m - 1][x] * (2.0 / 3.0);
      if (x >= 1) {
        P1[m][x] += P1[m - 1][x - 1] * (1.0 / 3.0);
      }
    }
  }
}

void initSP() {
  for (int m = 0; m <= MAX_M; m++)
    for (int x = 0; x <= MAX_M; x++)
      SP[m][x] = 0;
  for (int m = 0; m <= MAX_M; m++) {
    SP[m][0] = 1;
    for (int x = 1; x <= m; x++) {
      SP[m][x] = SP[m][x - 1] - P1[m][x - 1];
    }
    assert(EQ(SP[m][m], P1[m][m]));
  }
}

void dump() {
  printf("SP:\\n");
  for (int i = 0; i <= M; i++) {
    for (int j = 0; j <= i; j++) {
      printf("%3.3f ", SP[i][j]);
    }
    printf("\\n");
  }
}

double memo[MAX_M + 5][6][3];
double top(int x, int p, int t, const vector<int> &V) {
  static double dp[MAX_N + 1][5];
  // if (memo[x][p][t] > -1e9) return memo[x][p][t];
  int k = V[1];
  int P = x * k;
  for (int i = 0; i <= N; i++)
    for (int j = 0; j <= 4; j++)
      dp[i][j] = 0;
  dp[1][1] = 1.0;
  dp[1][4] = 1.0;
  for (int i = 2; i <= N; i++) {
    double X = SP[M][(P + V[i] - 1) / V[i]];
    dp[i][1] = dp[i - 1][1] * (1.0 - X);
    dp[i][2] = dp[i - 1][2] * (1.0 - X) + dp[i - 1][1] * X;
    dp[i][3] = dp[i - 1][3] * (1.0 - X) + dp[i - 1][2] * X;

    dp[i][4] = dp[i - 1][4] * X;
  }
  return (dp[N][1] + dp[N][2] + dp[N][3]) * p - dp[N][4] * 1;
  // return memo[x][p][t] = (dp[N][1] + dp[N][2] + dp[N][3]) * p - dp[N][4] * 1;
}

void solve() {
  double ans = -1e9;
  for (int i = 0; i <= M; i++)
    for (int j = 0; j <= 6; j++)
      for (int k = 0; k < 3; k++)
        memo[i][j][k] = -1e9;
  for (int x = 0; x <= M; x++) {
    for (int y = 0; y <= M - x; y++) {
      int z = M - (x + y);
      // viをx, daをy, voをz回行う
      ans = max(ans, top(x, 5, 0, vi) + top(y, 3, 1, da) + top(z, 2, 2, vo));
    }
  }
  printf("%.8lf\\n", ans);
}

int main() {
  cin >> N >> M;
  vi.clear();
  da.clear();
  vo.clear();
  vi.resize(N + 1);
  da.resize(N + 1);
  vo.resize(N + 1);
  for (int i = 1; i <= N; i++)
    cin >> vi[i] >> da[i] >> vo[i];
  initP1();
  initSP();
  solve();
  return 0;
}