BZOJ 3676 回文串

这题可以用回文自动机做。

然而我不会回文自动机所以就用了Manacher+SA

快速搞出每个回文串的位置和长度很明显可以马拉车

但是问题是怎么不重复算

如果一个串重复算那么这个\(SA\)就完全走不动了

考虑\(Manacher\)什么时候会碰到新串。

然后如果每次扩展都不能碰到\(maxR\)即极限右边界

那么就不能算是出现新串

如果破坏了边界就正常统计出现次数就好。

很奇怪的是求\(Height\)的时候不能加\(\leq n\)的判断 不然会挂 这玩意卡了我一晚上

关于\(Manacher\)落在原串的位置上的判断考虑奇偶位置也就是有效符的影响

也就是\((l+1)/2,r/2\)

UPD : 找到锅锅了 应该是 i + k < n && j + k < n

原因是a串是0开始的 一句话的后边知道减前边不知道减还行

#include<cstdio>
#include<cstring>
#include<iostream>
const int N = 5e5+7;typedef long long ll;
const int inf = 998244353;
inline int min(int a, int b) {return a > b ? b : a;}
inline ll max(ll a, ll b) {return a > b ? a : b;}
int ss[N*2], sa[N*2], x[N*2], y[N*2], c[N*2], rk[N*2], het[N*2];
const int upMAX = 1e6 + 7; char a[N*2]; 
int qlog[upMAX], st[N*2][22];int n, m;
inline void getSA() {
  for (int i = 1; i <= n; i++) c[x[i] = a[i - 1]]++;
  for (int i = 1; i <= m; i++) c[i] += c[i - 1];
  for (int i = 1; i <= n; i++) sa[c[x[i]]--] = i;
  for (int siz = 1, p = 0; siz <= n; siz <<= 1, p = 0) {
    for (int i = n - siz + 1; i <= n; i++) y[++p] = i;
    for (int i = 1; i <= n; i++) if (sa[i] > siz) y[++p] = sa[i] - siz;
    for (int i = 1; i <= m; i++) c[i] = 0;
    for (int i = 1; i <= n; i++) c[x[y[i]]]++;
    for (int i = 1; i <= m; i++) c[i] += c[i - 1];
    for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
    std :: swap(x, y), x[sa[1]] = 1, p = 1;
    for (int i = 2; i <= n; i++) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && 
      y[sa[i] + siz] == y[sa[i - 1] + siz]) ? p : ++p;
    if (n == p) break; m = p;
  } int k = 0;
  for (int i = 1; i <= n; i++) rk[sa[i]] = i;
  for (int i = 1; i <= n; i++) {
    if (k) k--; int j = sa[rk[i] - 1];
    while (i + k < n && j + k < n && a[i + k - 1] == a[j + k - 1]) k++;
    het[rk[i]] = k;
  } qlog[1] = 0;
  for (int i = 2; i < upMAX; i++) qlog[i] = qlog[i / 2] + 1;
  for (int i = 1; i <= n; i++) st[i][0] = het[i];
  int logw = qlog[n]; 
  for (int i = 1; i <= logw; i++) for (int j = 1; j + (1 << i) - 1 <= n; j++) 
    st[j][i] = min(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
}
inline int query(int x, int y) {
  if (x == y) return inf; if (x > y) return 0; x++; int logw = qlog[y - x + 1], ans;
  ans = min(st[x][logw], st[y - (1 << logw) + 1][logw]); return ans;
} int hw[N*2], sw[N*2];
ll LastANS;
inline void calc(int xL, int yR) {
  xL = (xL + 1) >> 1, (yR) = (yR) >> 1;
  int Len = yR - xL + 1, pos = rk[xL];
  int l = 1, r = pos, ansL = pos, ansR = pos;
  while (l < r) { 
    int mid = (l + r) >> 1;
    if (query(mid, pos) >= Len) r = mid;
    else l = mid + 1;  
  } ansL = r;
  l = pos , r = n;
  while (l < r) {
    int mid = (l + r + 1) >> 1;
    if (query(pos, mid) >= Len) l = mid;
    else r = mid - 1;
  } ansR = l;
  LastANS = max(LastANS, (ll)(ansR - ansL + 1)*(ll)Len);
} int res;
inline void Manacher() {
  sw[0] = sw[1] = '#';
  for (int i = 0; i < res; i++) 
    sw[(i << 1) + 2] = a[i], sw[(i << 1) + 3] = '#';
  int upn = res * 2 + 2, maxR = 0, MID = 0; sw[upn] = 0;
  for (int i = 0; i < upn; i++) {
    if (i < maxR) hw[i] = min(hw[(MID << 1) - i], hw[MID] + MID - i);
    else hw[i] = 1;
    while (sw[i + hw[i]] == sw[i - hw[i]]) {
      hw[i]++;
      if (i + hw[i] > maxR) calc(i - hw[i] + 1, i + hw[i] - 1);
    } if (i + hw[i] > maxR) maxR = i + hw[i], MID = i;
  } 
}
int main() {
  scanf("%s", a), n = strlen(a); m = 127; res = n;
  getSA(); Manacher();
  printf ("%lld", (ll)(LastANS));
}
posted @ 2019-10-08 21:38  ComeIntoCalm  阅读(64)  评论(0编辑  收藏  举报