【BZOJ】3676 [Apio2014]回文串
阿新 • • 發佈:2017-06-06
esp ret 結點 += lap first trees db4 lld
【算法】回文樹
【題解】建回文數,然後一個回文子串出現的次數就是結點被訪問的次數以及能包含它的結點被訪問的次數。
根據fail樹反向建新樹,那麽答案就是結點所在子樹的權值和(權值就是結點被訪問次數)。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=300010; char s[maxn]; int n,len,l,sz,first[maxn],tot; long long ans; struct trees{int len,fail,t[30View Code],num;}t[maxn]; struct edges{int v,from;}e[maxn*3]; void insert(int u,int v) {tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;} int getfail(int x) { while(s[len-t[x].len-1]!=s[len])x=t[x].fail; return x; } void tree_work() { int x=s[++len]-‘a‘; l=getfail(l); if(!t[l].t[x]) { sz++; t[sz].len=t[l].len+2; t[sz].num=1; t[sz].fail=t[getfail(t[l].fail)].t[x];//偏小 insert(t[sz].fail,sz); t[l].t[x]=sz; } else { t[t[l].t[x]].num++; } l=t[l].t[x]; } long long dfs(int x) { long long sum=t[x].num; for(int i=first[x];i;i=e[i].from) { sum+=dfs(e[i].v); } ans=max(ans,1ll*t[x].len*sum); return sum; } int main() { scanf("%s",s+1); n=strlen(s+1); sz=1; s[0]=-1;// t[0].len=0;t[1].len=-1; t[0].fail=t[1].fail=1; t[0].num=t[1].num=1; insert(1,0); len=l=ans=0; for(int i=1;i<=n;i++)tree_work(); dfs(1); printf("%lld",ans); return 0; }
【BZOJ】3676 [Apio2014]回文串