#1445 : 后缀自动机二·重复旋律5
时间限制:10000ms
单点时限:2000ms
内存限制:256MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中出现了多少不同的旋律?
输入
共一行,包含一个由小写字母构成的字符串。字符串长度不超过 1000000。
输出
一行一个整数,表示答案。
- 样例输入
-
aab
- 样例输出
-
5
后缀自动机,学习了最短路的转移。
1 /************************************************************************* 2 > File: main.cpp 3 > Author: You Siki 4 > Mail: You.Siki@outlook.com 5 > Time: 2016年12月23日 星期五 14时25分55秒 6 ************************************************************************/ 7 8 #include<bits/stdc++.h> 9 10 //using namespace std; 11 12 const int maxn = 2000005; 13 14 /* AUTOMATON */ 15 16 int last = 1; 17 int tail = 2; 18 int step[maxn]; 19 int fail[maxn]; 20 int mini[maxn]; 21 int next[maxn][26]; 22 23 inline void buildAutomaton(char *s) 24 { 25 while (*s) 26 { 27 int p = last; 28 int t = tail++; 29 int c = *s++ - 'a'; 30 step[t] = step[p] + 1; 31 while (p && !next[p][c]) 32 next[p][c] = t, p = fail[p]; 33 if (p) 34 { 35 int q = next[p][c]; 36 if (step[q] == step[p] + 1) 37 fail[t] = q, mini[t] = step[q] + 1; 38 else 39 { 40 int k = tail++; 41 fail[k] = fail[q]; 42 fail[q] = fail[t] = k; 43 step[k] = step[p] + 1; 44 mini[q] = step[k] + 1; 45 mini[t] = step[k] + 1; 46 for (int i = 0; i < 26; ++i) 47 next[k][i] = next[q][i]; 48 while (p && next[p][c] == q) 49 next[p][c] = k, p = fail[p]; 50 mini[k] = step[fail[k]] + 1; 51 } 52 } 53 else 54 fail[t] = 1, mini[t] = 1; 55 last = t; 56 } 57 } 58 59 inline long long solve(void) 60 { 61 long long ret = 0; 62 for (int i = 2; i < tail; ++i) 63 ret += step[i] - mini[i] + 1; 64 return ret; 65 } 66 67 /* MAIN FUNC */ 68 69 char str[maxn]; 70 71 signed main(void) 72 { 73 scanf("%s", str); 74 buildAutomaton(str); 75 printf("%lld ", solve()); 76 }
20170222 复习SAM模板
1 #include <cstdio> 2 #include <cstring> 3 4 const int siz = 2000005; 5 6 int last = 1; 7 int tail = 2; 8 int mini[siz]; 9 int maxi[siz]; 10 int fail[siz]; 11 int next[siz][26]; 12 13 inline void build(char *s) 14 { 15 while (*s) 16 { 17 int p = last; 18 int t = tail++; 19 int c = *s++ - 'a'; 20 21 maxi[t] = maxi[p] + 1; 22 23 while (p && !next[p][c]) 24 next[p][c] = t, p = fail[p]; 25 26 if (p) 27 { 28 int q = next[p][c]; 29 30 if (maxi[q] == maxi[p] + 1) 31 fail[t] = q, mini[t] = maxi[q] + 1; 32 else 33 { 34 int k = tail++; 35 36 fail[k] = fail[q]; 37 fail[t] = fail[q] = k; 38 maxi[k] = maxi[p] + 1; 39 mini[q] = maxi[k] + 1; 40 mini[t] = maxi[k] + 1; 41 mini[k] = maxi[fail[k]] + 1; 42 43 memcpy(next[k], next[q], 26 * sizeof(int)); 44 45 while (next[p][c] == q) 46 next[p][c] = k, p = fail[p]; 47 } 48 } 49 else 50 fail[t] = 1, mini[t] = 1; 51 52 last = t; 53 } 54 } 55 56 inline void calc(void) 57 { 58 long long ans = 0; 59 60 for (int i = 2; i < tail; ++i) 61 ans += maxi[i] - mini[i] + 1; 62 63 printf("%lld ", ans); 64 } 65 66 signed main(void) 67 { 68 static char s[siz]; 69 70 scanf("%s", s); 71 72 build(s); 73 74 calc(); 75 }
@Author: YouSiki