BZOJ3676: [Apio2014]回文串
阿新 • • 發佈:2018-02-28
pro sin mil fin namespace find 簡單 article struct
題解:
3.求串S內回文串的個數(其實就是1和2結合起來)
4.求以下標i結尾的回文串的個數
【傳送門:BZOJ3676】
簡要題意:
給出一個字符串,每一個回文子串的價值為這個回文子串出現的次數*回文子串的長度,求出價值最大的回文子串的價值
題解:
%%%又是一道新算法
本來想用AC自動機+馬拉車搞一下的,結果不會
hzwer大佬的題解用了後綴自動機+馬拉車
但是後綴自動機太難了
這時引出我們的新算法——回文樹
算法詳解,以及推薦代碼風格
簡單來說,回文樹可以解決以下問題:
1.求串S前綴0~i內本質不同回文串的個數(兩個串長度不同或者長度相同且至少有一個字符不同便是本質不同)
2.求串S內每一個本質不同回文串出現的次數
3.求串S內回文串的個數(其實就是1和2結合起來)
4.求以下標i結尾的回文串的個數
幾乎很多回文問題均可解決
而這道題就是回文樹裸題了,直接在加入節點是順便統計一下個數,最後按fail邊自下而上更新一下即可
參考代碼:
#include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; typedef long long LL; structTree { int len,fail,son[26]; }tr[310000]; char st[310000]; int len,last,tot,cnt[310000]; void ready() { tr[0].len=0;tr[1].len=-1; tr[0].fail=1; tot=1;last=0; } int findfail(int i,int j) { while(st[i-tr[j].len-1]!=st[i]) j=tr[j].fail; return j; } void add(int i,int x) {int j=findfail(i,last); if(tr[j].son[x]==0) { tr[++tot].len=tr[j].len+2; tr[tot].fail=tr[findfail(i,tr[j].fail)].son[x]; tr[j].son[x]=tot; } last=tr[j].son[x]; cnt[last]++; } LL getans() { LL ans=0; for(int i=tot;i>1;i--) { cnt[tr[i].fail]+=cnt[i]; ans=max(ans,LL(tr[i].len)*LL(cnt[i])); } return ans; } int main() { scanf("%s",st+1); len=strlen(st+1); ready(); for(int i=1;i<=len;i++) add(i,st[i]-‘a‘); printf("%lld",getans()); }
BZOJ3676: [Apio2014]回文串