码迷,mamicode.com
首页 > 其他好文 > 详细

CF1080E Sonya and Matrix Beauty - 哈希 + manacher

时间:2020-01-03 10:44:14      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:clu   main   cpp   sizeof   多少   矩阵   mod   esc   枚举   

Description

给定一个 \(n \times m\) 的字符矩阵,请求出有多少个子矩阵在重排子矩阵每一行的字符后,使得子矩阵的每行每列都是回文串。

Solution

如果一行能构成回文串,那么最多只能有一种字符出现奇数次。

如果一个矩阵的每一行和每一列都是回文串,那么除了满足上面的要求外,第\(i\)行和第\(n-i+1\)的每种字母出现的次数必须都相同。

所以我们可以枚举两列,然后对每一行的字母把出现次数\(hash\)起来,然后就是求由每一行的哈希值构成的序列的回文子串个数,\(manacher\)解决即可。

另外要注意的是如果某一行不能构成回文串,那么不应该计入到\(manacher\)的统计中去。

Code

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int _ = 500 + 10;
const int base = 233;
const ll mod = 20190816170251;
int N, M, cnt[_][_][30], p[_];
char s[_][_];
ll H[_][_], val[_][_], t[_], ans;

ll Hash(int *a) {
  ll ret = 0;
  for (int i = 1; i <= 26; ++i) ret = (ret * base % mod + a[i]) % mod;
  return ret;
}

bool check(int i, int l, int r) {
  ll x = val[i][r] ^ val[i][l - 1];
  return (!x) || (!(x - (x & (-x))));
}

void manacher() {
  memset(p, 0, sizeof(p));
  for (int i = 1, r = 0, mid = 0; i <= N * 2; ++i) {
    if (t[i] < 0) continue;
    if (i < r) p[i] = min(r - i, p[mid * 2 - i]);
    while (i - p[i] >= 0 && i + p[i] <= N * 2 + 1 && t[i - p[i]] == t[i + p[i]])
      ++p[i];
    if (i + p[i] > r) r = i + p[i] - 1, mid = i;
    // printf("%d\n", p[i]);
    ans += p[i] / 2;
  }
}

int main() {
#ifndef ONLINE_JUDGE
  freopen("matrix.in", "r", stdin);
  freopen("matrix.out", "w", stdout);
#endif
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= N; ++i) {
    scanf("%s", s[i] + 1);
    for (int j = 1; j <= M; ++j) {
      for (int k = 1; k <= 26; ++k) cnt[i][j][k] = cnt[i][j - 1][k];
      ++cnt[i][j][s[i][j] - 'a' + 1];
      H[i][j] = Hash(cnt[i][j]);
      val[i][j] = val[i][j - 1] ^ (1 << (s[i][j] - 'a'));
    }
  }
  for (int i = 1; i <= M; ++i) {
    for (int j = i; j <= M; ++j) {
      for (int k = 1; k <= N; ++k) {
        t[k * 2 - 1] = 0;
        if (check(k, i, j))
          t[k * 2] = (H[k][j] - H[k][i - 1] + mod) % mod;
        else
          t[k * 2] = -1ll * k;
      }
      manacher();
    }
  }
  printf("%lld\n", ans);
  return 0;
}

CF1080E Sonya and Matrix Beauty - 哈希 + manacher

标签:clu   main   cpp   sizeof   多少   矩阵   mod   esc   枚举   

原文地址:https://www.cnblogs.com/newbielyx/p/12143449.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!