[bzoj3238]差异

对于len(Ti),len(Tj),随意乱搞就行了。

对于lcp(Ti,Tj),很显然如果将所有的后缀都搞出来的话比较好弄。

既然是要求lcp的和,那么搞到后缀树上去找节点就行了。

因为后缀树有压缩,所以没有分叉,直接树上dp就行。(即使有分叉也没啥卵用。)

但是如何统计分叉呢?

计数原理。

对于每一个分叉,很显然构成的后缀的数量是在所有结束集合中任选两个,那么就是C2sz[x],那么就好搞了,最后乘上一个长度。

 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 }
View Code

 

转载于:https://www.cnblogs.com/KingSann/articles/6440139.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值