[bzoj3238]差异
对于len(Ti),len(Tj),随意乱搞就行了。
对于lcp(Ti,Tj),很显然如果将所有的后缀都搞出来的话比较好弄。
既然是要求lcp的和,那么搞到后缀树上去找节点就行了。
因为后缀树有压缩,所以没有分叉,直接树上dp就行。(即使有分叉也没啥卵用。)
但是如何统计分叉呢?
计数原理。
对于每一个分叉,很显然构成的后缀的数量是在所有结束集合中任选两个,那么就是C2sz[x],那么就好搞了,最后乘上一个长度。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <string> 7 #include <vector> 8 #include <cmath> 9 #include <queue> 10 #include <complex> 11 #include <set> 12 using namespace std; 13 14 const int N=1500000; 15 16 int ch[N][30],len[N],pre[N],r[N],tot=1,last=1; 17 int to[N],head[N],rest[N],num; 18 int p,np,q,nq; 19 long long ans; 20 char str[N]; 21 22 void add(int u,int v){ 23 to[++num]=v; 24 rest[num]=head[u]; 25 head[u]=num; 26 } 27 28 int nd(int l){return len[++tot]=l,tot;} 29 30 void add(int v){ 31 last=np=nd(len[p=last]+1); 32 pre[np]=r[np]=1; 33 while(p&&!ch[p][v])ch[p][v]=np,p=pre[p]; 34 if(p){ 35 pre[np]=q=ch[p][v]; 36 if(len[p]+1!=len[q]){ 37 nq=nd(len[p]+1); 38 memcpy(ch[nq],ch[q],sizeof ch[q]); 39 pre[nq]=pre[q],pre[q]=pre[np]=nq; 40 while(p&&ch[p][v]==q)ch[p][v]=nq,p=pre[p]; 41 } 42 } 43 } 44 45 void dp(int x){ 46 for(int i=head[x];i;i=rest[i]){ 47 dp(to[i]); 48 r[x]+=r[to[i]]; 49 } 50 ans-=(long long)r[x]*(r[x]-1)*(len[x]-len[pre[x]]); 51 } 52 53 int main(){ 54 scanf("%s",str); 55 int len=strlen(str); 56 ans=(long long)len*(len-1)*(len+1)/2; 57 for(int i=len-1;i>=0;i--)add(str[i]-'a'); 58 for(int i=2;i<=tot;i++)add(pre[i],i); 59 for(int i=head[1];i;i=rest[i])dp(to[i]); 60 printf("%lld\n",ans); 61 }