Codeforces Round #524 Div2 E

https://codeforces.com/problemset/problem/1080/E

问题

给一个字符方阵,如果能够存在一种方式,将一个子方阵每一行的字符按一定方式排列后,子方阵的每一行、每一列都是回文的,那么我们说这个子方阵是稳的。

问多少个子方阵是稳的。

题解

考虑一下一个子方阵稳的充要条件:

  1. 这一行的字符集能够在重排后回文(分奇偶讨论)。
  2. 对应行的字符集相同。

枚举一下列的范围 \([L,R]\),条件一暴力检查即可,条件二可以通过哈希解决,然后把哈希后的值用 Manacher 处理。

复杂度 \(O(26 \cdot N^{3})\),写法优秀的话可以达到 \(O(N^3)\)

#include <bits/stdc++.h>

using namespace std;

template <typename T>
vector<int> manacher(int n, const T &s, const function<bool(int)> &ignore) {
  if (n == 0) {
    return vector<int>();
  }
  vector<int> res(2 * n - 1);
  for (int z = 0, l = -1, r = -1; z < 2 * n - 1; z++) {
    int i = (z + 1) >> 1;
    if (z % 2 == 0 && ignore(i)) {
      continue;
    }
    int j = z >> 1;
    int p = i >= r ? 0 : min(r - i, res[2 * (l + r) - z]);
    for (; i - p - 1 >= 0 && j + p + 1 < n; p++) {
      if (!(s[i - p - 1] == s[j + p + 1]) || ignore(i - p - 1) || ignore(j + p + 1)) {
        break;
      }
    }
    res[z] = p;
    if (j + p > r) {
      l = i - p;
      r = j + p;
    }
  }
  return res;
}

template <typename T>
vector<int> manacher(const T &s, const function<bool(int)> &ignore) {
  return manacher(s.size(), s, ignore);
}

const int N = 300;
const unsigned long long B = 19260817;

unsigned long long a[N][N], pw[40];
int n, m, cnt[N][N][26];
char tmp[N];

int main() {
  pw[0] = 1;
  for (int i = 1; i < 40; i++) {
    pw[i] = pw[i - 1] * B;
  }
  scanf("%d %d", &n, &m);
  for (int i = 0; i < n; i++) {
    scanf("%s", tmp);
    unsigned long long hashh = 0;
    for (int j = 0; j < m; j++) {
      int c = tmp[j] - 'a';
      for (int d = 0; d < 26; d++) {
        cnt[i][j + 1][d] = cnt[i][j][d];
      }
      cnt[i][j + 1][c]++;
      hashh += pw[c];
      a[i][j + 1] = hashh;
    }
  }
  long long ans = 0;
  vector<unsigned long long> s(n);
  vector<char> ok(n);
  const auto ignore = [&](int i) {
    return ok[i];
  };
  for (int l = 1; l <= m; l++) {
    for (int r = l; r <= m; r++) {
      for (int i = 0; i < n; i++) {
        int codd = ~(r - l) & 1;
        for (int c = 0; c < 26; c++) {
          int have = cnt[i][r][c] - cnt[i][l - 1][c];
          codd -= (have & 1);
        }
        s[i] = a[i][r] - a[i][l - 1];
        ok[i] = (codd != 0);
      }
      vector<int> res = manacher(s, ignore);
      for (int z = 0; z < 2 * n - 1; z++) {
        ans += res[z] + (z % 2 == 0 && !ignore(z >> 1));
      }
    }
  }
  printf("%lld\n", ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/hfccccccccccccc/p/10015815.html