https://codeforces.com/problemset/problem/1080/E
问题
给一个字符方阵,如果能够存在一种方式,将一个子方阵每一行的字符按一定方式排列后,子方阵的每一行、每一列都是回文的,那么我们说这个子方阵是稳的。
问多少个子方阵是稳的。
题解
考虑一下一个子方阵稳的充要条件:
- 这一行的字符集能够在重排后回文(分奇偶讨论)。
- 对应行的字符集相同。
枚举一下列的范围 \([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;
}