hihoCoder #1445 : 后缀自动机二·重复旋律5

#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\n", 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\n", 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 }
View Code

 

@Author: YouSiki

 

posted @ 2016-12-23 15:12  YouSiki  阅读(261)  评论(0编辑  收藏  举报