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

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <complex>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

typedef long long ll;
// common

#define BR "\\n"
#define ALL(c) (c).begin(), (c).end()
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define EACH(it, o) for (auto it = (o).begin(); it != (o).end(); ++it)
#define IN(l, v, r) ((l) <= (v) && (v) < (r))

// config
// #undef NDEBUG
// #define INF 1<<30
// #define EPS 1e-8
// const ll MOD =100000007;

// debug
#ifdef NDEBUG
#define DUMP(x)
#define DUMPLN(x)
#define DEBUG(x)
#define DEBUGLN(x)
#define LINE()
#define LINELN()
#define CHECK(exp, act)
#define STOP(e)
#else
#define DUMP(x) cerr << #x << " = " << (x)
#define DUMPLN(x) DUMP(x) << endl
#define DEBUG(x) DUMP(x) << LINE() << " " << __FILE__
#define DEBUGLN(x) DEBUG(x) << endl
#define LINE() cerr << " (L" << __LINE__ << ")"
#define LINELN() LINE() << endl
#define CHECK(exp, act)                                                        \\
  if (exp != act) {                                                            \\
    DUMPLN(exp);                                                               \\
    DEBUGLN(act);                                                              \\
  }
#define STOP(e)                                                                \\
  CHECK(e, true);                                                              \\
  if (!(e))                                                                    \\
    exit(1);
#endif

// output
template <typename T> ostream &operator<<(ostream &os, const vector<T> &as) {
  REP(i, as.size()) {
    if (i != 0)
      os << " ";
    os << as[i];
  }
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<vector<T>> &as) {
  REP(i, as.size()) {
    if (i != 0)
      os << endl;
    os << as[i];
  }
  return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &ss) {
  for (auto a : ss) {
    if (a != ss.begin())
      os << " ";
    os << a;
  }
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  os << p.first << " " << p.second;
  return os;
}
template <typename K, typename V>
ostream &operator<<(ostream &os, const map<K, V> &m) {
  bool isF = true;
  for (auto &p : m) {
    if (!isF)
      os << endl;
    os << p;
    isF = false;
  }
  return os;
}
template <typename T1> ostream &operator<<(ostream &os, const tuple<T1> &t) {
  os << get<0>(t);
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const tuple<T1, T2> &t) {
  os << get<0>(t) << " " << get<1>(t);
  return os;
}
template <typename T1, typename T2, typename T3>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4, T5> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t)
     << " " << get<4>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4, T5, T6> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t)
     << " " << get<4>(t) << " " << get<5>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4, T5, T6, T7> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t)
     << " " << get<4>(t) << " " << get<5>(t) << " " << get<6>(t);
  return os;
}

template <typename T, typename V> inline T mod(T v, V MOD) {
  return (v % MOD + MOD) % MOD;
}

struct UnionFind {
  vector<int> par, rank, ss;
  int size;
  UnionFind(int n) {
    REP(i, n) par.push_back(i);
    rank = vector<int>(n);
    ss = vector<int>(n, 1);
    size = n;
  }
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]);
  }
  bool same(int x, int y) { return root(x) == root(y); }
  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return;
    if (rank[x] > rank[y])
      swap(x, y);
    par[x] = y;
    ss[y] += ss[x];
    if (rank[x] == rank[y])
      rank[x]++;
    size--;
  }
  int getS(int x) { return ss[root(x)]; }
};

ll MOD = 1000000007;

static const int M = 1050;
int dp[M][M][2]; // 偶数連結成分の数,奇数連結成分の数,連結成分を変えないで開いてる辺
                 // mod2

class Main {
public:
  int dfs(int en, int on, int ec) {
    if (dp[en][on][ec] != -1)
      return dp[en][on][ec];
    if (en + on == 1)
      return dp[en][on][ec] = 1;

    bool win = false;
    // edge
    if (ec > 0)
      win |= !dfs(en, on, 0);
    // e,e -> e
    if (en >= 2)
      win |= !dfs(en - 1, on, 1 - ec);
    // e,o -> o
    if (en >= 1 && on >= 1)
      win |= !dfs(en - 1, on, 1 - ec);
    // o,o -> e
    if (on >= 2)
      win |= !dfs(en + 1, on - 2, ec);
    return dp[en][on][ec] = win;
  }

  void run() {
    int N;
    cin >> N;
    vector<string> es(N);
    REP(i, N) cin >> es[i];
    UnionFind uf(N);
    REP(y, N) REP(x, N) if (es[y][x] == 'Y') uf.unite(y, x);
    map<int, int> ge;
    REP(y, N) ge[uf.root(y)] = uf.getS(y) * (uf.getS(y) - 1) / 2;

    REP(y, N)
    for (int x = y + 1; x < N; x++) if (es[y][x] == 'Y') ge[uf.root(y)]--;

    int en = 0, on = 0, ec = 0;
    EACH(it, ge) {
      if (uf.getS(it->first) % 2)
        on++;
      else
        en++;
      ec += it->second;
      ec %= 2;
    }
    fill_n(dp[0][0], M * M * 2, -1);
    cout << (dfs(en, on, ec) ? "Taro" : "Hanako") << endl;
  }
};

int main() {
  ios::sync_with_stdio(false);
  Main().run();
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <complex>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

typedef long long ll;
// common

#define BR "\\n"
#define ALL(c) (c).begin(), (c).end()
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define EACH(it, o) for (auto it = (o).begin(); it != (o).end(); ++it)
#define IN(l, v, r) ((l) <= (v) && (v) < (r))

// config
// #undef NDEBUG
// #define INF 1<<30
// #define EPS 1e-8
// const ll MOD =100000007;

// debug
#ifdef NDEBUG
#define DUMP(x)
#define DUMPLN(x)
#define DEBUG(x)
#define DEBUGLN(x)
#define LINE()
#define LINELN()
#define CHECK(exp, act)
#define STOP(e)
#else
#define DUMP(x) cerr << #x << " = " << (x)
#define DUMPLN(x) DUMP(x) << endl
#define DEBUG(x) DUMP(x) << LINE() << " " << __FILE__
#define DEBUGLN(x) DEBUG(x) << endl
#define LINE() cerr << " (L" << __LINE__ << ")"
#define LINELN() LINE() << endl
#define CHECK(exp, act)                                                        \\
  if (exp != act) {                                                            \\
    DUMPLN(exp);                                                               \\
    DEBUGLN(act);                                                              \\
  }
#define STOP(e)                                                                \\
  CHECK(e, true);                                                              \\
  if (!(e))                                                                    \\
    exit(1);
#endif

// output
template <typename T> ostream &operator<<(ostream &os, const vector<T> &as) {
  REP(i, as.size()) {
    if (i != 0)
      os << " ";
    os << as[i];
  }
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<vector<T>> &as) {
  REP(i, as.size()) {
    if (i != 0)
      os << endl;
    os << as[i];
  }
  return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &ss) {
  for (auto a : ss) {
    if (a != ss.begin())
      os << " ";
    os << a;
  }
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  os << p.first << " " << p.second;
  return os;
}
template <typename K, typename V>
ostream &operator<<(ostream &os, const map<K, V> &m) {
  bool isF = true;
  for (auto &p : m) {
    if (!isF)
      os << endl;
    os << p;
    isF = false;
  }
  return os;
}
template <typename T1> ostream &operator<<(ostream &os, const tuple<T1> &t) {
  os << get<0>(t);
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const tuple<T1, T2> &t) {
  os << get<0>(t) << " " << get<1>(t);
  return os;
}
template <typename T1, typename T2, typename T3>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4, T5> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t)
     << " " << get<4>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4, T5, T6> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t)
     << " " << get<4>(t) << " " << get<5>(t);
  return os;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
          typename T6, typename T7>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4, T5, T6, T7> &t) {
  os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t)
     << " " << get<4>(t) << " " << get<5>(t) << " " << get<6>(t);
  return os;
}

template <typename T, typename V> inline T mod(T v, V MOD) {
  return (v % MOD + MOD) % MOD;
}

struct UnionFind {
  vector<int> par, rank, ss;
  int size;
  UnionFind(int n) {
    REP(i, n) par.push_back(i);
    rank = vector<int>(n);
    ss = vector<int>(n, 1);
    size = n;
  }
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]);
  }
  bool same(int x, int y) { return root(x) == root(y); }
  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return;
    if (rank[x] > rank[y])
      swap(x, y);
    par[x] = y;
    ss[y] += ss[x];
    if (rank[x] == rank[y])
      rank[x]++;
    size--;
  }
  int getS(int x) { return ss[root(x)]; }
};

ll MOD = 1000000007;

static const int M = 1050;
int dp[M][M][2]; // 偶数連結成分の数,奇数連結成分の数,連結成分を変えないで開いてる辺
                 // mod2

class Main {
public:
  int dfs(int en, int on, int ec) {
    if (en + on == 1)
      return dp[en][on][ec] = 1;

    bool win = false;
    // edge
    if (ec > 0)
      win |= !dfs(en, on, 0);
    // e,e -> e
    if (en >= 2)
      win |= !dfs(en - 1, on, 1 - ec);
    // e,o -> o
    if (en >= 1 && on >= 1)
      win |= !dfs(en - 1, on, 1 - ec);
    // o,o -> e
    if (on >= 2)
      win |= !dfs(en + 1, on - 2, ec);
    return dp[en][on][ec] = win;
  }

  void run() {
    int N;
    cin >> N;
    vector<string> es(N);
    REP(i, N) cin >> es[i];
    UnionFind uf(N);
    REP(y, N) REP(x, N) if (es[y][x] == 'Y') uf.unite(y, x);
    map<int, int> ge;
    REP(y, N) ge[uf.root(y)] = uf.getS(y) * (uf.getS(y) - 1) / 2;

    REP(y, N)
    for (int x = y + 1; x < N; x++) if (es[y][x] == 'Y') ge[uf.root(y)]--;

    int en = 0, on = 0, ec = 0;
    EACH(it, ge) {
      if (uf.getS(it->first) % 2)
        on++;
      else
        en++;
      ec += it->second;
      ec %= 2;
    }
    fill_n(dp[0][0], M * M * 2, -1);
    cout << (dfs(en, on, ec) ? "Taro" : "Hanako") << endl;
  }
};

int main() {
  ios::sync_with_stdio(false);
  Main().run();
  return 0;
}