BZOJ 3676 [Apio2014]回文串(回文樹)
阿新 • • 發佈:2017-07-12
代碼 nbsp 一個 字符 ast div 題目 cpp sin
【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3676
【題目大意】
考慮一個只包含小寫拉丁字母的字符串s。
我們定義s的一個子串t的"出現值"為t在s中的出現次數乘以t的長度。
求s的所有回文子串中的最大出現值。
【題解】
我們對給出串建立回文樹,統計每個回文串出現次數和長度,相乘取組大即可
【代碼】
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=300010,S=26; int all,son[N][S],fail[N],cnt[N],len[N],text[N],last,tot; int newnode(int l){ for(int i=0;i<S;i++)son[tot][i]=0; cnt[tot]=0,len[tot]=l; return tot++; } void init(){ last=tot=all=0; newnode(0),newnode(-1); text[0]=-1,fail[0]=1; } int getfail(int x){ while(text[all-len[x]-1]!=text[all])x=fail[x]; return x; } void add(int w){ text[++all]=w; int x=getfail(last); if(!son[x][w]){ int y=newnode(len[x]+2); fail[y]=son[getfail(fail[x])][w]; son[x][w]=y; }cnt[last=son[x][w]]++; } void count(){for(int i=tot-1;~i;i--)cnt[fail[i]]+=cnt[i];} char s[N]; int main(){ while(~scanf("%s",s)){ int n=strlen(s); init(); for(int i=0;i<n;i++)add(s[i]-‘a‘); count(); long long ans=0; for(int i=0;i<tot;i++)ans=max(ans,1LL*cnt[i]*len[i]); printf("%lld\n",ans); }return 0; }
BZOJ 3676 [Apio2014]回文串(回文樹)