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

// respect cos's solution!!

#include <cstdio>
#include <cstring>
#include <vector>

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

using namespace std;

class union_find {
  vector<int> a;

public:
  union_find(int n) : a(n, -1) {}
  int find(int x) {
    if (a[x] < 0)
      return x;
    return a[x] = find(a[x]);
  }
  void unite(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) {
      a[x] += a[y];
      a[y] = x;
    }
  }
  int size(int x) { return -a[find(x)]; }
};

// even : 頂点数が偶数である連結成分の個数
// odd  : 頂点数が奇数である連結成分の個数
// e : 連結成分の個数を変えずに追加できる辺数 mod 2
int dp[1001][1001][2];
int dfs(int even, int odd, int e) {
  int &res = dp[even][odd][e];
  if (res != -1)
    return res;

  if (even + odd == 1)
    return res = 1;

  if (e == 1 && !dfs(even, odd, 0))
    return res = 1;

  if (even >= 2 && !dfs(even - 1, odd, e ^ 1))
    return res = 1;
  if (odd >= 2 && !dfs(even + 1, odd - 2, e))
    return res = 1;
  if (even >= 1 && odd >= 1 && !dfs(even - 1, odd, e ^ 1))
    return res = 1;

  return res = 0;
}

int main() {
  int n;
  scanf("%d", &n);
  static char adj[1000][1001];
  rep(u, n) scanf("%s", adj[u]);

  union_find U(n);
  rep(u, n) rep(v, u) if (adj[u][v] == 'Y') U.unite(u, v);

  int even = 0, odd = 0, cnt[1000];
  bool vis[1000] = {};
  rep(u, n) {
    int i = U.find(u);
    if (!vis[i]) {
      vis[i] = true;
      if (U.size(u) % 2 == 0)
        even++;
      else
        odd++;
      cnt[i] = U.size(u) * (U.size(u) - 1) / 2;
    }
  }
  rep(u, n) rep(v, u) if (adj[u][v] == 'Y') cnt[U.find(u)]--;

  int e = 0;
  rep(i, n) if (vis[i] && cnt[i] % 2 == 1) e ^= 1;

  memset(dp, -1, sizeof dp);
  puts(dfs(even, odd, e) ? "Taro" : "Hanako");

  return 0;
}

Error: TLE

Fixed submission:

// respect cos's solution!!

#include <cstdio>
#include <vector>

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

using namespace std;

class union_find {
  vector<int> a;

public:
  union_find(int n) : a(n, -1) {}
  int find(int x) {
    if (a[x] < 0)
      return x;
    return a[x] = find(a[x]);
  }
  void unite(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) {
      a[x] += a[y];
      a[y] = x;
    }
  }
  int size(int x) { return -a[find(x)]; }
};

// even : 頂点数が偶数である連結成分の個数
// odd  : 頂点数が奇数である連結成分の個数
// e : 連結成分の個数を変えずに追加できる辺数 mod 2
int dfs(int even, int odd, int e) {
  if (even + odd == 1)
    return 1;

  if (e == 1 && !dfs(even, odd, 0))
    return 1;

  if (even >= 2 && !dfs(even - 1, odd, e ^ 1))
    return 1;
  if (odd >= 2 && !dfs(even + 1, odd - 2, e))
    return 1;
  if (even >= 1 && odd >= 1 && !dfs(even - 1, odd, e ^ 1))
    return 1;

  return 0;
}

int main() {
  int n;
  scanf("%d", &n);
  static char adj[1000][1001];
  rep(u, n) scanf("%s", adj[u]);

  union_find U(n);
  rep(u, n) rep(v, u) if (adj[u][v] == 'Y') U.unite(u, v);

  int even = 0, odd = 0, cnt[1000];
  bool vis[1000] = {};
  rep(u, n) {
    int i = U.find(u);
    if (!vis[i]) {
      vis[i] = true;
      if (U.size(u) % 2 == 0)
        even++;
      else
        odd++;
      cnt[i] = U.size(u) * (U.size(u) - 1) / 2;
    }
  }
  rep(u, n) rep(v, u) if (adj[u][v] == 'Y') cnt[U.find(u)]--;

  int e = 0;
  rep(i, n) if (vis[i] && cnt[i] % 2 == 1) e ^= 1;

  puts(dfs(even, odd, e) ? "Taro" : "Hanako");

  return 0;
}