bzoj 3238差异

3238: [Ahoi2013]差异

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1420  Solved: 662
[Submit][Status][Discuss]

Description

Input

一行,一个字符串S

Output

一行,一个整数,表示所求值

Sample Input

cacao

Sample Output


54

HINT



2<=N<=500000,S由小写英文字母组成

 
题解:
right集合:pnt树上的子树sz大小(不统计nq节点)
把串倒过来建后缀自动机,两个状态的lcp是pnt树上lca的val,也是串中两个前缀的最长公共后缀,即为原串的最长公共前缀。
一个点的所有儿子的每个出现位置两两的lcp均为这个点的val,剩下的是减去子树内lcp更长的串的贡献。注意减去的应该是sz[i]*sz[i - 1],而不是子树去重后的答案
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define maxn 1000020
 6 
 7 typedef long long LL;
 8 struct node{
 9     int next[27],val,pnt;
10 }sam[maxn];
11 int a[maxn],num[maxn],sz[maxn];
12 int n,m,root,tot,last;
13 LL ans,f[maxn],g[maxn];
14 char ch[maxn];
15 
16 inline void add(int x){
17     int np = ++tot,p = last;
18     sam[np].val = sam[p].val + 1;
19     sz[np] = 1;
20     while ( p && !sam[p].next[x] ) sam[p].next[x] = np , p = sam[p].pnt;
21     int q = sam[p].next[x];
22     if ( !q ) sam[p].next[x] = np , sam[np].pnt = p;
23     else if ( q && sam[p].val + 1 == sam[q].val ) sam[np].pnt = q;
24     else{
25         int nq = ++tot;
26         sam[nq].val = sam[p].val + 1;
27         sam[nq].pnt = sam[q].pnt;
28         sam[q].pnt = sam[np].pnt = nq;
29         memcpy(sam[nq].next,sam[q].next,sizeof(sam[q].next));
30         while ( p && sam[p].next[x] == q ) sam[p].next[x] = nq , p = sam[p].pnt;
31         if ( sam[p].next[x] == q ) sam[p].next[x] = nq;
32     }
33     last = np;
34 }
35 inline void getsort(){
36     for (int i = 1 ; i <= tot ; i++) num[sam[i].val]++;
37     for (int i = 1 ; i <= n ; i++) num[i] += num[i - 1];
38     for (int i = 1 ; i <= tot ; i++) a[num[sam[i].val]--] = i;
39     for (int i = tot ; i >= 1 ; i--) {
40         sz[sam[a[i]].pnt] += sz[a[i]];
41            f[a[i]] += (LL)sz[a[i]] * (sz[a[i]] - 1);
42         f[sam[a[i]].pnt] -= (LL)sz[a[i]] * (sz[a[i]] - 1);
43     }
44 }
45 int main(){
46     scanf("%s",ch + 1);
47     n = strlen(ch + 1);
48     for (int i = n ; i >= 1 ; i--){
49         add(ch[i] - 'a');
50     }
51     getsort();
52     ans = (LL)(n + 1) * n * (n - 1) >> 1;
53     for (int i = 1 ; i <= tot ; i++) ans -= f[i] * (LL)sam[i].val;
54     printf("%lld
",ans);
55     return 0;
56 }
View Code
 
原文地址:https://www.cnblogs.com/zqq123/p/5282793.html