【BZOJ3238】差异【后缀自动机+dp】

题意

分析

 这个题目还是很优秀的。sigma(len(Ti)+len(Tj))的值是一定的=n*(n+1)*(n-1)/2。那么关键就是求任意两个后缀的lcp的和了。

  我们怎么求两个后缀的lcp?如果用后缀自动机的话,我们可以先把字符串反过来,然后建后缀自动机,那么两个后缀的lcp就是他们两个在parent树上的最近公共祖先(lca)的len。我们要求的是任意两个后缀的lcp的和,我们可以考虑在parent上跑树形dp。令dp[u]为以u为lca的lcp的和。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 
 6 using namespace std;
 7 typedef long long LL;
 8 const int maxn=500000+100;
 9 int n;
10 char s[maxn];
11 struct state{
12     int len,link;
13     int next[26];
14 }st[2*maxn];
15 int last,cur,sz;
16 int c[2*maxn],cnt[2*maxn];
17 LL dp[2*maxn];
18 void init(){
19     sz=1;
20     last=cur=0;
21     st[0].link=-1;
22     st[0].len=0;
23 }
24 void build_sam(int c){
25     cur=sz++;
26     cnt[cur]=1;
27     st[cur].len=st[last].len+1;
28     int p;
29     for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link)
30         st[p].next[c]=cur;
31     if(p==-1)
32         st[p].link=0;
33     else{
34         int q=st[p].next[c];
35         if(st[q].len==st[p].len+1)
36             st[cur].link=q;
37         else{
38             int clone=sz++;
39             st[clone].len=st[p].len+1;
40             st[clone].link=st[q].link;
41             for(int i=0;i<26;i++)
42                 st[clone].next[i]=st[q].next[i];
43             for(;p!=-1&&st[p].next[c]==q;p=st[p].link)
44                 st[p].next[c]=clone;
45             st[cur].link=st[q].link=clone;
46         }
47     }
48     last=cur;
49 }
50 int cmp(int a,int b){
51     return st[a].len>st[b].len;
52 }
53 int main(){
54     scanf("%s",s);
55     n=strlen(s);
56     init();
57     for(int i=0;i<n;i++)
58         build_sam(s[i]-'a');
59     for(int i=0;i<sz;i++)
60         c[i]=i;
61     sort(c,c+sz,cmp );
62     for(int i=0;i<sz;i++){
63         int o=c[i];
64         if(st[o].link!=-1){
65             dp[st[o].link]+=(LL)st[st[o].link].len*cnt[o]*cnt[st[o].link];
66             cnt[st[o].link]+=cnt[o];
67         }
68     }
69 
70     LL ans=(LL)n*(n+1)*(n-1)/2;
71     for(int i=0;i<sz;i++){
72         ans-=2*dp[i];
73     }
74     printf("%lld\n",ans);
75 
76 return 0;
77 }
View Code

 

posted @ 2018-11-01 14:56  蒟蒻LQL  阅读(273)  评论(0编辑  收藏  举报