[bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增

Brief Description

一个回文串的value定义为这个回文串的长度乘以出现次数。给定一个字符串,求\(value_{max}\)

Algorithm Design

我们使用Manacher暴力算出所有的回文子串,放在SAM里倍增,大力算贡献就好了。

Code

#include <algorithm>
#include <cstdio>
#define ll long long
#include <cstring>
const int maxn = 600010;
int n;
ll ans;
int p[maxn];
char str[maxn];
struct Suffix_Automaton {
  int trans[maxn][26], fa[maxn][20], pos[maxn], len[maxn], size[maxn];
  int last, root, sz;
  int v[maxn], q[maxn], dep[maxn];
  void init() {
    sz = 0;
    last = root = ++sz;
  }
  void insert(int x, int id) {
    int p = last, np = last = ++sz;
    len[np] = len[p] + 1;
    pos[id] = np;
    size[np] = 1;
    for (; !trans[p][x]; p = fa[p][0])
      trans[p][x] = np;
    if (p == 0)
      fa[np][0] = root;
    else {
      int q = trans[p][x];
      if (len[q] == len[p] + 1) {
        fa[np][0] = q;
      } else {
        int nq = ++sz;
        for (int i = 0; i < 26; i++)
          trans[nq][i] = trans[q][i];
        fa[nq][0] = fa[q][0];
        len[nq] = len[p] + 1;
        fa[q][0] = fa[np][0] = nq;
        for (; trans[p][x] == q; p = fa[p][0])
          trans[p][x] = nq;
      }
    }
  }
  void pre() {
    for (int i = 1; i <= sz; i++)
      v[len[i]]++;
    for (int i = 1; i <= n; i++)
      v[i] += v[i - 1];
    for (int i = sz; i >= 1; i--)
      q[v[len[i]]--] = i;
    for (int i = sz; i >= 1; i--) {
      int t = q[i];
      size[fa[t][0]] += size[t];
    }
    for (int i = 1; i <= sz; i++) {
      int t = q[i];
      dep[t] = dep[fa[t][0]] + 1;
      for (int j = 1; (1 << j) <= dep[t]; j++)
        fa[t][i] = fa[fa[t][i - 1]][i - 1];
    }
  }
  void query(int l, int r) {
    int ret = pos[r];
    for (int i = 19; i >= 0; i--) {
      int t = fa[ret][i];
      if (len[t] >= r - l + 1)
        ret = t;
    }
    ans = std::max(ans, (ll)size[ret] * (r - l + 1));
  }
} sam;
void manacher() {
  int mx = 1, id = 1;
  for (int i = n; i; i--)
    str[i * 2] = '#', str[i * 2 - 1] = str[i];
  n <<= 1;
  for (int i = 1; i <= n; i++) {
    p[i] = std::min(p[id * 2 - i], mx - i);
    while (i - p[i] > 0 && str[i - p[i]] == str[i + p[i]]) {
      int al = (i - p[i]) / 2 + 1;
      int ar = (i + p[i] + 1) / 2;
      // printf("%d %d\n", al, ar);
      sam.query(al, ar);
      p[i]++;
    }
    if (i + p[i] > mx)
      mx = i + p[i], id = i;
  }
}
int main() {
#ifndef ONLINE_JUDGE
// freopen("input", "r", stdin);
#endif
  scanf("%s", str + 1);
  n = strlen(str + 1);
  str[0] = '+', str[n + 1] = '-';
  sam.init();
  for (int i = 1; i <= n; i++) {
    sam.insert(str[i] - 'a', i);
  }
  sam.pre();
  manacher();
  printf("%lld\n", ans);
}

posted on 2017-03-15 15:24 蒟蒻konjac 阅读(...) 评论(...) 编辑 收藏

统计