Problem p03917 (C++)

Buggy submission (status: Runtime Error):
#include "algorithm"
#include "bitset"
#include "cassert"
#include "climits"
#include "cmath"
#include "cstdio"
#include "functional"
#include "iomanip"
#include "iostream"
#include "list"
#include "map"
#include "numeric"
#include "queue"
#include "random"
#include "set"
#include "stack"
#include "string"
#include "unordered_map"
#include "unordered_set"

using namespace std;

// const long long int MOD = 1000000007;
const int MOD = 1000000007;
// const int MOD = 998244353;

long long int N, M, K, H, W, L, R;
// int N, M, K, H, W, L, R;

class UnionFind {
  vector<int> parent;
  vector<int> rank;

public:
  UnionFind(int num) {
    num++;
    parent.resize(num);
    rank.resize(num);
    for (int i = 0; i < num; i++) {
      parent[i] = i;
      rank[i] = 0;
    }
  }
  int Find(int node) {
    if (parent[node] == node)
      return node;
    else
      return parent[node] = Find(parent[node]);
  }
  void Unite(int u, int v) {
    u = Find(u);
    v = Find(v);
    if (u == v)
      return;
    if (rank[u] < rank[v])
      parent[u] = v;
    else {
      parent[v] = u;
      if (rank[u] == rank[v])
        rank[u]++;
    }
  }
  bool Check_Same(int u, int v) { return Find(u) == Find(v); }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> H >> W;
  vector<string> s(H);
  for (auto &i : s)
    cin >> i;
  if (H == 1) {
    auto t = s[0];
    reverse(t.begin(), t.end());
    if (s[0] == t) {
      cout << 1 << endl;
    } else
      cout << 2 << endl;
    return 0;
  }
  if (W == 1) {
    auto t = s;
    reverse(t.begin(), t.end());
    if (s == t)
      cout << 1 << endl;
    else
      cout << 2 << endl;
    return 0;
  }
  long long int ans = 1;
  if (H <= 3 || W <= 3) {
    for (int i = 0; i < H / 2; i++) {
      for (int j = 0; j < W / 2; j++) {
        vector<char> v;
        v.push_back(s[i][j]);
        v.push_back(s[H - i - 1][W - j - 1]);
        v.push_back(s[H - i - 1][j]);
        v.push_back(s[i][W - j - 1]);
        set<vector<char>> sv;
        sort(v.begin(), v.end());
        do {
          sv.insert(v);
        } while (next_permutation(v.begin(), v.end()));
        ans *= sv.size();
        ans %= MOD;
      }
    }
    if (H & 1) {
      // assert(0);
      bool flag = false;
      for (int j = 0; j < W / 2; j++) {
        if (s[H / 2][j] != s[H / 2][W - j - 1])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    if (W & 1) {
      bool flag = false;
      for (int j = 0; j < H / 2; j++) {
        if (s[j][W / 2] != s[H - j - 1][W / 2])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    cout << ans << endl;
  } else {
    long long int ans = 1;
    if (H & 1) {
      // assert(0);
      bool flag = false;
      for (int j = 0; j < W / 2; j++) {
        if (s[H / 2][j] != s[H / 2][W - j - 1])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    if (W & 1) {
      bool flag = false;
      for (int j = 0; j < H / 2; j++) {
        if (s[j][W / 2] != s[H - j - 1][W / 2])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    vector<vector<int>> box(H / 2, vector<int>(W / 2));
    for (int i = 0; i < H / 2; i++) {
      for (int j = 0; j < W / 2; j++) {
        vector<char> v;
        v.push_back(s[i][j]);
        v.push_back(s[H - i - 1][W - j - 1]);
        v.push_back(s[H - i - 1][j]);
        v.push_back(s[i][W - j - 1]);
        set<vector<char>> sv;
        sort(v.begin(), v.end());
        do {
          sv.insert(v);
        } while (next_permutation(v.begin(), v.end()));
        ans *= min(12, (int)sv.size());
        ans %= MOD;
        if (sv.size() > 12)
          box[i][j] = 1;
      }
    }
    UnionFind uf(H / 2 + W / 2);
    for (int i = 0; i < H / 2; i++) {
      for (int j = 0; j < W / 2; j++) {
        if (box[i][j])
          uf.Unite(i, j + H / 2);
      }
    }
    int sz = 0;
    for (int i = 0; i < H + 2 + W / 2; i++) {
      if (uf.Find(i) == i)
        sz++;
    }
    for (int i = 0; i < H / 2 + W / 2 - sz; i++) {
      ans <<= 1;
      ans %= MOD;
    }
    cout << ans << endl;
  }
  return 0;
}

Fixed submission:
#include "algorithm"
#include "bitset"
#include "cassert"
#include "climits"
#include "cmath"
#include "cstdio"
#include "functional"
#include "iomanip"
#include "iostream"
#include "list"
#include "map"
#include "numeric"
#include "queue"
#include "random"
#include "set"
#include "stack"
#include "string"
#include "unordered_map"
#include "unordered_set"

using namespace std;

// const long long int MOD = 1000000007;
const int MOD = 1000000007;
// const int MOD = 998244353;

long long int N, M, K, H, W, L, R;
// int N, M, K, H, W, L, R;

class UnionFind {
  vector<int> parent;
  vector<int> rank;

public:
  UnionFind(int num) {
    num++;
    parent.resize(num);
    rank.resize(num);
    for (int i = 0; i < num; i++) {
      parent[i] = i;
      rank[i] = 0;
    }
  }
  int Find(int node) {
    if (parent[node] == node)
      return node;
    else
      return parent[node] = Find(parent[node]);
  }
  void Unite(int u, int v) {
    u = Find(u);
    v = Find(v);
    if (u == v)
      return;
    if (rank[u] < rank[v])
      parent[u] = v;
    else {
      parent[v] = u;
      if (rank[u] == rank[v])
        rank[u]++;
    }
  }
  bool Check_Same(int u, int v) { return Find(u) == Find(v); }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> H >> W;
  vector<string> s(H);
  for (auto &i : s)
    cin >> i;
  if (H == 1) {
    auto t = s[0];
    reverse(t.begin(), t.end());
    if (s[0] == t) {
      cout << 1 << endl;
    } else
      cout << 2 << endl;
    return 0;
  }
  if (W == 1) {
    auto t = s;
    reverse(t.begin(), t.end());
    if (s == t)
      cout << 1 << endl;
    else
      cout << 2 << endl;
    return 0;
  }
  long long int ans = 1;
  if (H <= 3 || W <= 3) {
    for (int i = 0; i < H / 2; i++) {
      for (int j = 0; j < W / 2; j++) {
        vector<char> v;
        v.push_back(s[i][j]);
        v.push_back(s[H - i - 1][W - j - 1]);
        v.push_back(s[H - i - 1][j]);
        v.push_back(s[i][W - j - 1]);
        set<vector<char>> sv;
        sort(v.begin(), v.end());
        do {
          sv.insert(v);
        } while (next_permutation(v.begin(), v.end()));
        ans *= sv.size();
        ans %= MOD;
      }
    }
    if (H & 1) {
      // assert(0);
      bool flag = false;
      for (int j = 0; j < W / 2; j++) {
        if (s[H / 2][j] != s[H / 2][W - j - 1])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    if (W & 1) {
      bool flag = false;
      for (int j = 0; j < H / 2; j++) {
        if (s[j][W / 2] != s[H - j - 1][W / 2])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    cout << ans << endl;
  } else {
    long long int ans = 1;
    if (H & 1) {
      // assert(0);
      bool flag = false;
      for (int j = 0; j < W / 2; j++) {
        if (s[H / 2][j] != s[H / 2][W - j - 1])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    if (W & 1) {
      bool flag = false;
      for (int j = 0; j < H / 2; j++) {
        if (s[j][W / 2] != s[H - j - 1][W / 2])
          flag = true;
      }
      if (flag)
        ans <<= 1;
      ans %= MOD;
    }
    vector<vector<int>> box(H / 2, vector<int>(W / 2));
    for (int i = 0; i < H / 2; i++) {
      for (int j = 0; j < W / 2; j++) {
        vector<char> v;
        v.push_back(s[i][j]);
        v.push_back(s[H - i - 1][W - j - 1]);
        v.push_back(s[H - i - 1][j]);
        v.push_back(s[i][W - j - 1]);
        set<vector<char>> sv;
        sort(v.begin(), v.end());
        do {
          sv.insert(v);
        } while (next_permutation(v.begin(), v.end()));
        ans *= min(12, (int)sv.size());
        ans %= MOD;
        if (sv.size() > 12)
          box[i][j] = 1;
      }
    }
    UnionFind uf(H / 2 + W / 2);
    for (int i = 0; i < H / 2; i++) {
      for (int j = 0; j < W / 2; j++) {
        if (box[i][j])
          uf.Unite(i, j + H / 2);
      }
    }
    int sz = 0;
    for (int i = 0; i < H / 2 + W / 2; i++) {
      if (uf.Find(i) == i)
        sz++;
    }
    for (int i = 0; i < H / 2 + W / 2 - sz; i++) {
      ans <<= 1;
      ans %= MOD;
    }
    cout << ans << endl;
  }
  return 0;
}