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

#include <algorithm>
#include <cstdio>
#include <cstring>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

struct piece {
  int h, w;       // 大きさ
  char B[20][21]; // ピースの形
  int y0, x0;     // 空きじゃない一番左上のマス
  bool operator==(const piece &P) const {
    if (h != P.h || w != P.w)
      return false;
    rep(y, h) rep(x, w) if (B[y][x] != P.B[y][x]) return false;
    return true;
  }
};

void find_upperleft(piece &P, char c) {
  rep(y, P.h) rep(x, P.w) if (P.B[y][x] == c) {
    P.y0 = y;
    P.x0 = x;
    return;
  }
}

piece W; // 枠

int n, n2[10]; // n2[i] := ( ピース i の、回転で一致しないパターンの個数 )
piece P[10][4]; // ピースの情報 ( 回転 4 パターン )

int m;
int choice[10]; // プレイヤーが選ぶピースの番号 ( 選んだら -1 )

bool dfs() {
  if (count(choice, choice + m, -1) == m)
    return true;

  find_upperleft(W, '.');
  int y0 = W.y0,
      x0 = W.x0; // 再帰した先で W.y0, W.x0 の値が変わるのでローカルにもっておく
  rep(i, m) if (choice[i] != -1) {
    int &u = choice[i];
    rep(k, n2[u]) {
      int tmp;
      const piece &Q = P[u][k];

      bool ok = false;
      // ピース Q をはめこむ
      rep(y, Q.h) rep(x, Q.w) {
        int yy = y + y0 - Q.y0, xx = x + x0 - Q.x0; // 枠における座標
        if (0 <= yy && yy < W.h && 0 <= xx && xx < W.w) {
          if (Q.B[y][x] == '#') {
            if (W.B[yy][xx] == '.') {
              W.B[yy][xx] = 'A' + i;
            } else
              goto CANNOT_SET;
          }
        } else {
          if (Q.B[y][x] == '#')
            goto CANNOT_SET;
        }
      }

      // ピース Q をはめたので次のピースへ
      tmp = u;
      u = -1;
      ok = dfs();
      u = tmp;

    CANNOT_SET:
      // ピース Q を抜く
      rep(y, Q.h) rep(x, Q.w) {
        int yy = y + y0 - Q.y0, xx = x + x0 - Q.x0;
        if (0 <= yy && yy < W.h && 0 <= xx && xx < W.w &&
            W.B[yy][xx] == 'A' + i)
          W.B[yy][xx] = '.';
      }

      if (ok)
        return true;
    }
  }

  return false;
}

int main() {
  for (; scanf("%d%d", &W.h, &W.w), W.h;) {
    rep(i, W.h) scanf("%s", W.B[i]);
    int W_sz = 0;
    rep(i, W.h) rep(j, W.w) if (W.B[i][j] == '.') W_sz++;

    scanf("%d", &n);
    int P_sz[10] = {};
    rep(i, n) {
      scanf("%d%d", &P[i][0].h, &P[i][0].w);
      rep(y, P[i][0].h) scanf("%s", P[i][0].B[y]);
      rep(k, 3) {
        P[i][k + 1].h = P[i][k].w;
        P[i][k + 1].w = P[i][k].h;
        rep(y, P[i][k].h) rep(x, P[i][k].w) {
          P[i][k + 1].B[x][P[i][k].h - y - 1] = P[i][k].B[y][x];
        }
      }
      rep(k, 4) find_upperleft(P[i][k], '#');

      rep(y, P[i][0].h) rep(x, P[i][0].w) if (P[i][0].B[y][x] == '#') P_sz[i]++;
    }

    // 回転で一致するものを削除することで高速化
    rep(i, n) {
      n2[i] = 4;
      rep(k, n2[i]) {
        bool b = false;
        rep(l, k) if (P[i][k] == P[i][l]) b = true;
        if (b) {
          memcpy(&P[i][k], &P[i][n2[i] - 1], sizeof(piece));
          n2[i]--;
          k--;
        }
      }
    }

    int q;
    scanf("%d", &q);
    while (q--) {
      scanf("%d", &m);
      rep(i, m) scanf("%d", choice + i), choice[i]--;

      int dif = W_sz;
      rep(i, m) dif -= P_sz[choice[i]];
      puts(dif == 0 && dfs() ? "YES" : "NO");
    }
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cstdio>
#include <cstring>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

struct piece {
  int h, w;       // 大きさ
  char B[20][21]; // ピースの形
  int y0, x0;     // 空きじゃない一番左上のマス
  bool operator==(const piece &P) const {
    if (h != P.h || w != P.w || y0 != P.y0 || x0 != P.x0)
      return false;
    rep(y, h) rep(x, w) if (B[y][x] != P.B[y][x]) return false;
    return true;
  }
};

void find_upperleft(piece &P, char c) {
  rep(y, P.h) rep(x, P.w) if (P.B[y][x] == c) {
    P.y0 = y;
    P.x0 = x;
    return;
  }
}

piece W; // 枠

int n, n2[10]; // n2[i] := ( ピース i の、回転で一致しないパターンの個数 )
piece P[10][4]; // ピースの情報 ( 回転 4 パターン )

int m;
int choice[10]; // プレイヤーが選ぶピースの番号 ( 選んだら -1 )

bool dfs() {
  if (count(choice, choice + m, -1) == m)
    return true;

  find_upperleft(W, '.');
  int y0 = W.y0,
      x0 = W.x0; // 再帰した先で W.y0, W.x0 の値が変わるのでローカルにもっておく
  rep(i, m) if (choice[i] != -1) {
    int &u = choice[i];
    int tmp = u;

    rep(k, n2[i]) {
      const piece &Q = P[u][k];

      bool ok = true;
      // ピース Q をはめこむ
      rep(y, Q.h) rep(x, Q.w) {
        int yy = y + y0 - Q.y0, xx = x + x0 - Q.x0; // 枠における座標
        if (0 <= yy && yy < W.h && 0 <= xx && xx < W.w) {
          if (Q.B[y][x] == '#') {
            if (W.B[yy][xx] == '.') {
              W.B[yy][xx] = 'A' + u;
            } else
              ok = false;
          }
        } else {
          if (Q.B[y][x] == '#')
            ok = false;
        }
      }

      bool end = false;
      if (ok) {
        u = -1;
        end = dfs();
        u = tmp;
      }

      // ピース Q を抜く
      rep(y, Q.h) rep(x, Q.w) {
        int yy = y + y0 - Q.y0, xx = x + x0 - Q.x0;
        if (0 <= yy && yy < W.h && 0 <= xx && xx < W.w &&
            W.B[yy][xx] == 'A' + u)
          W.B[yy][xx] = '.';
      }

      if (end)
        return true;
    }
  }

  return false;
}

int main() {
  for (; scanf("%d%d", &W.h, &W.w), W.h;) {
    rep(i, W.h) scanf("%s", W.B[i]);
    int W_sz = 0;
    rep(i, W.h) rep(j, W.w) if (W.B[i][j] == '.') W_sz++;

    scanf("%d", &n);
    int P_sz[10] = {};
    rep(i, n) {
      scanf("%d%d", &P[i][0].h, &P[i][0].w);
      rep(y, P[i][0].h) scanf("%s", P[i][0].B[y]);
      rep(k, 3) {
        P[i][k + 1].h = P[i][k].w;
        P[i][k + 1].w = P[i][k].h;
        rep(y, P[i][k].h) rep(x, P[i][k].w) {
          P[i][k + 1].B[x][P[i][k].h - y - 1] = P[i][k].B[y][x];
        }
      }
      rep(k, 4) find_upperleft(P[i][k], '#');

      rep(y, P[i][0].h) rep(x, P[i][0].w) if (P[i][0].B[y][x] == '#') P_sz[i]++;
    }

    // 回転で一致するものを削除することで高速化
    rep(i, n) {
      n2[i] = 4;
      rep(k, n2[i]) {
        bool b = false;
        rep(l, k) if (P[i][k] == P[i][l]) b = true;
        if (b) {
          memcpy(&P[i][k], &P[i][n2[i] - 1], sizeof(piece));
          n2[i]--;
          k--;
        }
      }
    }

    int q;
    scanf("%d", &q);
    while (q--) {
      scanf("%d", &m);
      rep(i, m) scanf("%d", choice + i), choice[i]--;

      int dif = W_sz;
      rep(i, m) dif -= P_sz[choice[i]];
      puts(dif == 0 && dfs() ? "YES" : "NO");
    }
  }

  return 0;
}