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

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>

using namespace std;

const double EPS = 1e-10;
bool EQ(double a, double b) { return abs(a - b) < EPS; }

double dp[511][111][111];
int H, N, P, M, K;
bool A[511];
bool B[511][111][111];
// double cnt;

double dfs(int i, int j, int k, double cnt) {
  if (dp[i][j][k] >= -0.5)
    return dp[i][j][k];
  if (i == H + 1) {
    // kは使い切っていなくても到達確率には問題ない？
    if (j == P && k == 0)
      return 1;
    return 0;
  }
  double res = 0;
  // この高さに線が存在
  if (A[i] != 0) {
    // 左へ移動
    if (j != 0 && B[i][j - 1][j])
      res = dfs(i + 1, j - 1, k, cnt);
    // 右へ移動
    else if (j + 1 != N && B[i][j][j + 1])
      res = dfs(i + 1, j + 1, k, cnt);
    // 移動なし
    else
      res = dfs(i + 1, j, k, cnt);
  } else {
    if (k >= 1) {
      if (j + 1 != N && j != 0) {
        // to left
        res += dfs(i + 1, j - 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // to right
        res += dfs(i + 1, j + 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // no move without bar
        if (cnt - k != 0)
          res += dfs(i + 1, j, k, cnt - 1) * ((1.0 * cnt - k) / cnt);
        // no move with bar
        res += dfs(i + 1, j, k - 1, cnt - 1) * (k / cnt) *
               (1.0 * (N - 3) / (N - 1));
      } else if (j != 0) {
        // to left
        res += dfs(i + 1, j - 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // no move without bar
        if (cnt - k != 0)
          res += (dfs(i + 1, j, k, cnt - 1)) * (1.0 * cnt - k) / cnt;
        // no move with bar
        res += dfs(i + 1, j, k - 1, cnt - 1) * (k / cnt) *
               (1.0 * (N - 2) / (N - 1));
      } else if (j + 1 != N) {
        // to right
        res += dfs(i + 1, j + 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // no move without bar
        if (cnt - k != 0)
          res += (dfs(i + 1, j, k, cnt - 1)) * (1.0 * cnt - k) / cnt;
        // no move with bar
        res += dfs(i + 1, j, k - 1, cnt - 1) * (k / cnt) *
               (1.0 * (N - 2) / (N - 1));
      }
    } else {
      // no move
      res += dfs(i + 1, j, k, cnt);
    }
  }
  return dp[i][j][k] = res;
}

int main() {

  while (cin >> H >> N >> P >> M >> K && (H | N | P | M | K)) {
    P--;
    double cnt = H;
    memset(A, 0, sizeof(A));
    memset(B, 0, sizeof(B));
    for (int i = 0; i < 511; i++)
      for (int j = 0; j < 111; j++)
        for (int k = 0; k < 111; k++)
          dp[i][j][k] = -1;
    int a, b;
    for (int i = 0; i < M; i++) {
      cnt--;
      cin >> a >> b;
      A[a] = true;
      b--;
      B[a][b][b + 1] = true;
      B[a][b + 1][b] = true;
    }
    double res = 0;
    for (int i = 0; i < N; i++) {
      if (!EQ(res, dfs(1, i, K, cnt)) && res < dfs(1, i, K, cnt))
        res = dfs(1, i, K, cnt);
    }
    printf("%.10f\\n", res);
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>

using namespace std;

const double EPS = 1e-10;
bool EQ(double a, double b) { return abs(a - b) < EPS; }

double dp[501][101][101];
int H, N, P, M, K;
bool A[511];
bool B[511][111][111];
// double cnt;

double dfs(int i, int j, int k, double cnt) {
  if (dp[i][j][k] >= -0.5)
    return dp[i][j][k];
  if (i == H + 1) {
    // kは使い切っていなくても到達確率には問題ない？
    if (j == P && k == 0)
      return 1;
    return 0;
  }
  double res = 0;
  // この高さに線が存在
  if (A[i] != 0) {
    // 左へ移動
    if (j != 0 && B[i][j - 1][j])
      res = dfs(i + 1, j - 1, k, cnt);
    // 右へ移動
    else if (j + 1 != N && B[i][j][j + 1])
      res = dfs(i + 1, j + 1, k, cnt);
    // 移動なし
    else
      res = dfs(i + 1, j, k, cnt);
  } else {
    if (k >= 1) {
      if (j + 1 != N && j != 0) {
        // to left
        res += dfs(i + 1, j - 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // to right
        res += dfs(i + 1, j + 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // no move without bar
        res += dfs(i + 1, j, k, cnt - 1) * ((1.0 * cnt - k) / cnt);
        // no move with bar
        res += dfs(i + 1, j, k - 1, cnt - 1) * (k / cnt) *
               (1.0 * (N - 3) / (N - 1));
      } else if (j != 0) {
        // to left
        res += dfs(i + 1, j - 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // no move without bar
        res += (dfs(i + 1, j, k, cnt - 1)) * (1.0 * cnt - k) / cnt;
        // no move with bar
        res += dfs(i + 1, j, k - 1, cnt - 1) * (k / cnt) *
               (1.0 * (N - 2) / (N - 1));
      } else if (j + 1 != N) {
        // to right
        res += dfs(i + 1, j + 1, k - 1, cnt - 1) * (k / cnt) * (1.0 / (N - 1));
        // no move without bar
        res += (dfs(i + 1, j, k, cnt - 1)) * (1.0 * cnt - k) / cnt;
        // no move with bar
        res += dfs(i + 1, j, k - 1, cnt - 1) * (k / cnt) *
               (1.0 * (N - 2) / (N - 1));
      }
    } else {
      // no move
      res += dfs(i + 1, j, k, cnt);
    }
  }
  return res;
}

int main() {

  while (cin >> H >> N >> P >> M >> K && (H | N | P | M | K)) {
    P--;
    double cnt = H;
    memset(A, 0, sizeof(A));
    memset(B, 0, sizeof(B));
    for (int i = 0; i < 501; i++)
      for (int j = 0; j < 101; j++)
        for (int k = 0; k < 101; k++)
          dp[i][j][k] = -1;
    int a, b;
    for (int i = 0; i < M; i++) {
      cnt--;
      cin >> a >> b;
      A[a] = true;
      b--;
      B[a][b][b + 1] = true;
      B[a][b + 1][b] = true;
    }
    double res = 0;
    for (int i = 0; i < N; i++)
      if (!EQ(res, dfs(1, i, K, cnt)) && res < dfs(1, i, K, cnt))
        res = dfs(1, i, K, cnt);
    printf("%.10f\\n", res);
  }

  return 0;
}