1. 程式人生 > >【BZOJ】3676 [Apio2014]回文串

【BZOJ】3676 [Apio2014]回文串

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[30
],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; }
View Code

【BZOJ】3676 [Apio2014]回文串