bzoj3238 [Ahoi2013]差异
地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3238
题目:
3238: [Ahoi2013]差异
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3367 Solved: 1532
[Submit][Status][Discuss]
Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
思路:
很明显前面的len[i]+len[j]是不变的,所以可以直接求出,对于后面的有俩种做法:
后缀自动机做法:
我们知道沿parent树往上走是不断取后缀,也就是不断删首字母。
所以如果把字符串反转,然后沿parent树往上走则是对前缀不断取前缀的过程,也就是不断删尾字母。
这时parent树就成lcp树,树上每个状态都是一些子串的lcp,所以树dp一下即可。
这个树dp部分有点巧妙,学习别人的,要我写会写成dfs的形式。
sam做法:
1 /************************************************************** 2 Problem: 3238 3 User: weeping 4 Language: C++ 5 Result: Accepted 6 Time:3356 ms 7 Memory:122876 kb 8 ****************************************************************/ 9 10 #include <bits/stdc++.h> 11 12 using namespace std; 13 14 struct SAM 15 { 16 static const int MAXN = 500002<<1;//大小为字符串长度两倍 17 static const int LetterSize = 26; 18 19 int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN]; 20 int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组 21 22 void init( void) 23 { 24 last = tot = 1; 25 len[1] = 0; 26 memset(ch,0,sizeof ch); 27 memset(fa,0,sizeof fa); 28 memset(cnt,0,sizeof cnt); 29 } 30 31 void add( int x) 32 { 33 int p = last, np = last = ++tot; 34 len[np] = len[p] + 1, cnt[last] = 1; 35 while( p && !ch[p][x]) ch[p][x] = np, p = fa[p]; 36 if( p == 0) 37 fa[np] = 1; 38 else 39 { 40 int q = ch[p][x]; 41 if( len[q] == len[p] + 1) 42 fa[np] = q; 43 else 44 { 45 int nq = ++tot; 46 memcpy( ch[nq], ch[q], sizeof ch[q]); 47 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq; 48 while( p && ch[p][x] == q) ch[p][x] = nq, p = fa[p]; 49 } 50 } 51 } 52 53 void toposort( void) 54 { 55 for(int i = 1; i <= len[last]; i++) sum[i] = 0; 56 for(int i = 1; i <= tot; i++) sum[len[i]]++; 57 for(int i = 1; i <= len[last]; i++) sum[i] += sum[i-1]; 58 for(int i = 1; i <= tot; i++) tp[sum[len[i]]--] = i; 59 } 60 61 void work(void) 62 { 63 toposort(); 64 long long ans=1LL*len[last]*(len[last]+1)*(len[last]-1)/2; 65 for(int i=tot;i;i--) 66 ans-=2LL*cnt[fa[tp[i]]]*len[fa[tp[i]]]*cnt[tp[i]],cnt[fa[tp[i]]]+=cnt[tp[i]]; 67 printf("%lld\n",ans); 68 } 69 } sam; 70 71 char sa[500005]; 72 73 int main( void) 74 { 75 scanf("%s",sa); 76 sam.init(); 77 for(int i=strlen(sa)-1;i>-1;i--) sam.add(sa[i]-'a'); 78 sam.work(); 79 return 0; 80 }
作者:weeping
出处:www.cnblogs.com/weeping/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。