Codeforces Round #524 Div2 E
阿新 • • 發佈:2018-11-25
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; }