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

【BZOJ】3676: [Apio2014]回文串

turn 算法 view 價值 using open 技術 con src

【題意】給定只含小寫字母的字符串s,定義價值為回文子串的長度*出現次數,求最大價值。n<=3*10^5。

【算法】回文樹

【題解】回文樹上一個點的被訪問次數是其作為最長回文子串的出現次數。

將fail邊反向連接建樹後,每個點的子樹訪問次數和就是這個回文子串的出現次數,可以dfs解決。

註意:要從-1點開始dfs才能保證到達所有點。記得開long long。

技術分享圖片
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const
int maxn=600010; int n,tot,len[maxn],fail[maxn],length,sz,nownode,ch[maxn][30],first[maxn],size[maxn]; ll ans=0; struct edge{int v,from;}e[maxn]; char s[maxn]; int getfail(int x){while(s[length-len[x]-1]!=s[length])x=fail[x];return x;} void build(){ int y=s[++length]-a; int x=getfail(nownode);
if(!ch[x][y]){ len[++sz]=len[x]+2; fail[sz]=ch[getfail(fail[x])][y]; ch[x][y]=sz; } size[ch[x][y]]++; nownode=ch[x][y]; } void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;} int dfs(int x){ ll sum=size[x]; for(int i=first[x];i;i=e[i].from
){ sum+=dfs(e[i].v); } ans=max(ans,sum*len[x]); return sum; } int main(){ scanf("%s",s+1); n=strlen(s+1); len[0]=0;fail[0]=1; len[1]=-1;fail[1]=1; length=0; sz=1;//!!! for(int i=1;i<=n;i++)build(); insert(1,0); for(int i=2;i<=sz;i++){ insert(fail[i],i); } dfs(1);//1 printf("%lld",ans); return 0; }
View Code

【BZOJ】3676: [Apio2014]回文串