您的位置:首页 > 其它

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

2016-12-23 15:12 477 查看

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

时间限制:10000ms
单点时限:2000ms
内存限制:256MB

描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。

现在小Hi想知道一部作品中出现了多少不同的旋律?

解题方法提示

输入

共一行,包含一个由小写字母构成的字符串。字符串长度不超过 1000000。

输出

一行一个整数,表示答案。

样例输入
aab

样例输出
5


后缀自动机,学习了最短路的转移。

/*************************************************************************
> File: main.cpp
> Author: You Siki
> Mail: You.Siki@outlook.com
> Time: 2016年12月23日 星期五 14时25分55秒
************************************************************************/

#include<bits/stdc++.h>

//using namespace std;

const int maxn = 2000005;

/* AUTOMATON */

int last = 1;
int tail = 2;
int step[maxn];
int fail[maxn];
int mini[maxn];
int next[maxn][26];

inline void buildAutomaton(char *s)
{
while (*s)
{
int p = last;
int t = tail++;
int c = *s++ - 'a';
step[t] = step[p] + 1;
while (p && !next[p][c])
next[p][c] = t, p = fail[p];
if (p)
{
int q = next[p][c];
if (step[q] == step[p] + 1)
fail[t] = q, mini[t] = step[q] + 1;
else
{
int k = tail++;
fail[k] = fail[q];
fail[q] = fail[t] = k;
step[k] = step[p] + 1;
mini[q] = step[k] + 1;
mini[t] = step[k] + 1;
for (int i = 0; i < 26; ++i)
next[k][i] = next[q][i];
while (p && next[p][c] == q)
next[p][c] = k, p = fail[p];
mini[k] = step[fail[k]] + 1;
}
}
else
fail[t] = 1, mini[t] = 1;
last = t;
}
}

inline long long solve(void)
{
long long ret = 0;
for (int i = 2; i < tail; ++i)
ret += step[i] - mini[i] + 1;
return ret;
}

/* MAIN FUNC */

char str[maxn];

signed main(void)
{
scanf("%s", str);
buildAutomaton(str);
printf("%lld\n", solve());
}


20170222 复习SAM模板

#include <cstdio>
#include <cstring>

const int siz = 2000005;

int last = 1;
int tail = 2;
int mini[siz];
int maxi[siz];
int fail[siz];
int next[siz][26];

inline void build(char *s)
{
while (*s)
{
int p = last;
int t = tail++;
int c = *s++ - 'a';

maxi[t] = maxi[p] + 1;

while (p && !next[p][c])
next[p][c] = t, p = fail[p];

if (p)
{
int q = next[p][c];

if (maxi[q] == maxi[p] + 1)
fail[t] = q, mini[t] = maxi[q] + 1;
else
{
int k = tail++;

fail[k] = fail[q];
fail[t] = fail[q] = k;
maxi[k] = maxi[p] + 1;
mini[q] = maxi[k] + 1;
mini[t] = maxi[k] + 1;
mini[k] = maxi[fail[k]] + 1;

memcpy(next[k], next[q], 26 * sizeof(int));

while (next[p][c] == q)
next[p][c] = k, p = fail[p];
}
}
else
fail[t] = 1, mini[t] = 1;

last = t;
}
}

inline void calc(void)
{
long long ans = 0;

for (int i = 2; i < tail; ++i)
ans += maxi[i] - mini[i] + 1;

printf("%lld\n", ans);
}

signed main(void)
{
static char s[siz];

scanf("%s", s);

build(s);

calc();
}


View Code

@Author: YouSiki
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: