1. 程式人生 > >[APIO2014]回文串

[APIO2014]回文串

小寫 lld pan n) aps cli man 快速 radius

題目描述

給你一個由小寫拉丁字母組成的字符串 ss 。我們定義 ss 的一個子串的存在值為這個子串在 ss 中出現的次數乘以這個子串的長度。

對於給你的這個字符串 ss ,求所有回文子串中的最大存在值。

輸入輸出格式

輸入格式:

一行,一個由小寫拉丁字母(a~z)組成的非空字符串 ss 。

輸出格式:

輸出一個整數,表示所有回文子串中的最大存在值。

輸入輸出樣例

輸入樣例#1:
abacaba
輸出樣例#1:
7
輸入樣例#2:
www
輸出樣例#2:
4

這道題好像是一道回文樹裸題

但是我並不會回文樹

可以用SA+manacher或SAM+manacher

最近剛學 SAM ,所以用 SAM+manacher 過掉了這道題

首先先對原串建立 SAM

然後跑 manacher ,一旦有回文串就在SAM上進行查詢

查詢 S(l , r)在原串中出現多少次

暴力查詢一次的復雜度是 O(n)

總復雜度 O(n^2)

顯然不能通過此題

所以我們可以考慮用倍增快速查詢出 S(l,r) 在原串中出現次數

st[i][j] 表示 SAM 上的節點i向上跳 2^j 步能到達哪個節點

如果當前節點的 step >= r - l + 1 就說明要查詢的回文串仍然是當前節點的一個後綴

就一直往上跳到不能再跳為止

此時的節點所代表的子串的 right 集合大小就是 S(l,r) 在原串中的出現次數辣

這樣的時間復雜度 O(nlogn),可以通過此題

技術分享圖片
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
# define LL long long
const int M = 600005 ;
using namespace std ;
char s[M] ;
int n , m ;
LL Ans ;
int Last , cnt ;
int size[M] , son[M][26] , fa[M] , step[M] , c[M] , b[M] ; int p[M] , r[M] , fir[M] ; int pos[M] , lg[M] , dep[M] , st[M][20] ; inline void Insert(int c , int id){ int np = ++cnt , p = Last ; step[np] = step[p] + 1 ; Last = cnt ; size[np] = 1 ; pos[id] = np ; while(!son[p][c] && p) son[p][c] = np , p = fa[p] ; if(!p) fa[np] = 1 ; else { int q = son[p][c] ; if(step[q] == step[p] + 1) fa[np] = q ; else{ int nq = ++cnt ; step[nq] = step[p] + 1 ; memcpy(son[nq] , son[q] , sizeof(son[q])) ; fa[nq] = fa[q] ; fa[q] = fa[np] = nq ; while(son[p][c] == q) son[p][c] = nq , p = fa[p] ; } } } inline void Build(){ Last = cnt = 1 ; for(int i = 1 ; i <= n ; i ++) Insert(s[i] - a , i) ; for(int i = 1 ; i <= cnt; i ++) c[step[i]] ++ ; for(int i = 1 ; i <= n ; i ++) c[i] += c[i - 1] ; for(int i = 1 ; i <= cnt; i ++) b[c[step[i]]--] = i ; for(int i = cnt , p ; i ; i --) { p = b[i] ; size[fa[p]] += size[p] ; } for(int i = 1 , p ; i <= cnt ; i ++) { p = b[i] ; dep[p] = dep[fa[p]] + 1 ; st[p][0] = fa[p] ; for(int j = 1 ; (1<<j) <= dep[p] ; j ++) st[p][j] = st[st[p][j - 1]][j - 1] ; } } inline void Check(int l , int r){ if(l < 1 || r > n) return ; int now = pos[r] ; for(int i = lg[dep[now]] ; i >= 0 ; i --) { int temp = st[now][i] ; if(step[temp] >= r - l + 1) now = temp ; } Ans = max(Ans , 1LL * size[now] * (r - l + 1)) ; } inline void Manacher() { p[++m] = @ ; for(int i = 1 ; i <= n ; i ++) p[++m] = # , p[++m] = s[i] , fir[m] = i ; p[++m] = # ; p[++m] = $ ; int pos = 0 , mx = 0 ; for(int i = 1 ; i <= m ; i ++) { if(i < mx) r[i] = min(mx - i , r[pos * 2 - i]) ; else r[i] = 1 ; Check(fir[i - r[i] + 2] , fir[i + r[i] - 2]) ; while(p[i - r[i]] == p[i + r[i]]) ++r[i] , Check(fir[i - r[i] + 2] , fir[i + r[i] - 2]) ; if(i + r[i] > mx) mx = i + r[i] , pos = i ; } } int main(){ scanf("%s",s + 1) ; n = strlen(s + 1) ; for(int i = 2 ; i <= n ; i ++) lg[i] = lg[i >> 1] + 1 ; Build() ; Manacher() ; printf("%lld\n",Ans) ; return 0 ; }
View Code

[APIO2014]回文串