BZOJ_3238_[Ahoi2013]差異_後綴自動機
阿新 • • 發佈:2018-05-13
esc mes https #define lld style char s 發現 組成
BZOJ_3238_[Ahoi2013]差異_後綴自動機
Description
Input
一行,一個字符串S
Output
一行,一個整數,表示所求值
Sample Input
cacaoSample Output
54HINT
2<=N<=500000,S由小寫英文字母組成
後綴數組做法:http://www.cnblogs.com/suika/p/8995997.html
可以發現兩個後綴的lcp長度一定是這兩個串在後綴樹上的lca的深度。
對後綴樹上每個結點維護子樹中葉子個數,然後向上走的時候統計一下有多少後綴兩兩的LCA在當前結點上即可。
代碼:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 500050 int ch[N<<1][27],fa[N<<1],dep[N<<1],cnt=1,lst=1,siz[N<<1]; char s[N]; int c[N<<1],a[N<<1]; void insert(int x) { int p=lst,np=++cnt,q,nq; lst=np; dep[np]=dep[p]+1; for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np; if(!p) fa[np]=1; else { q=ch[p][x]; if(dep[q]==dep[p]+1) fa[np]=q; else { fa[nq=++cnt]=fa[q]; dep[nq]=dep[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[q]=fa[np]=nq; for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq; } } siz[np]=1; } int main() { scanf("%s",s+1); int ln=strlen(s+1); int i; long long ans=0; for(i=ln;i;i--) insert(s[i]-‘a‘); for(i=1;i<=cnt;i++) c[dep[i]]++; for(i=1;i<=cnt;i++) c[i]+=c[i-1]; for(i=1;i<=cnt;i++) a[c[dep[i]]--]=i; for(i=cnt;i;i--) { int p=a[i]; ans+=1ll*siz[fa[p]]*siz[p]*dep[fa[p]]; siz[fa[p]]+=siz[p]; } printf("%lld\n",1ll*ln*(ln-1)*(ln+1)/2-2*ans); }
BZOJ_3238_[Ahoi2013]差異_後綴自動機