bzoj 3238差异
3238: [Ahoi2013]差异
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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\n",ans); 55 return 0; 56 }