zoukankan      html  css  js  c++  java
  • CF1080E Sonya and Matrix Beauty

    Description

    给定一个 (n imes 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
    ", 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
    ", ans);
      return 0;
    }
    
  • 相关阅读:
    【模板】O(nlongn)求LIS
    【图论】用线段树写Dijikstra!!
    【图论】最短路总结
    【codeforces841A】Generous Kefa
    【模板】Tarjian求LCA
    【模板】 RMQ求区间最值
    【模板】map入门
    【二分 贪心】覆盖问题 BZOJ1052 HAOI2007
    【dp】10-15题解 snake vs block
    【模拟】10-15 题解 trans
  • 原文地址:https://www.cnblogs.com/newbielyx/p/12143449.html
Copyright © 2011-2022 走看看