处理子矩阵的一般方法, 把多行压缩成一行,然后跑manacher, 压缩的话用hash就好了。
#include<bits/stdc++.h> using namespace std; using LL = long long; using ull = unsigned long long ; mt19937_64 rng(58); const int N = 250 + 7; const ull B = (int)1e6 + 3; int n, m; int c[N][N][26]; char s[N][N]; ull Pow[26]; ull V[N]; int p[N]; int odd; inline ull get(int row, int l, int r, int ch) { int cnt = c[row][r][ch] - c[row][l - 1][ch]; odd += cnt & 1; return cnt * Pow[ch]; } int manacher(ull *s, int n) { int ans = 0; s[0] = rng(); s[n + 1] = rng(); int mx = 0, id = 0; for(int i = 1; i <= n; i++) { if(mx > i) p[i] = min(mx - i, p[2 * id - i]); else p[i] = 1; while(s[i + p[i]] == s[i - p[i]]) p[i]++; if(i + p[i] > mx) mx = i + p[i], id = i; ans += p[i]; } mx = 0, id = 0; for(int i = 1; i <= n; i++) { if(mx > i) p[i] = min(mx - i, p[2 * id - i]); else p[i] = 0; while(s[i + p[i] + 1] == s[i - p[i]]) p[i]++; if(i + p[i] > mx) mx = i + p[i], id = i; ans += p[i]; } return ans; } int main() { for(int i = Pow[0] = 1; i < N; i++) Pow[i] = Pow[i - 1] * B; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { for(int k = 0; k < 26; k++) c[i][j][k] = c[i][j - 1][k]; c[i][j][s[i][j] - 'a']++; } } LL ans = 0; for(int cl = 1; cl <= m; cl++) { for(int cr = cl; cr <= m; cr++) { int tot = 0; for(int r = 1; r <= n; r++) { ull hs = 0; odd = 0; for(int ch = 0; ch < 26; ch++) { hs += get(r, cl, cr, ch); } V[r] = hs; if((cr - cl & 1) && odd || !(cr - cl & 1) && odd > 1) { ans += manacher(V, tot); tot = 0; } else { V[++tot] = hs; } } ans += manacher(V, tot); } } printf("%lld ", ans); return 0; }