1535: [POI2005]Sza-Template
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 372 Solved: 195
[ Submit][ Status][ Discuss]
Description
Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段作为模版. 然后将模版重复喷涂到相应的位置后就得到了他想要的字符序列.一个字符可以被喷涂很多次,但是一个位置不能喷涂不同的字符.做一个模版很费工夫,所以他想要模版的长度尽量小,求最小长度是多少.拿样例来说 ababbababbabababbabababbababbaba , 模版为前8个字符ababbaba, 喷涂的过程为: ababbababbabababbabababbababbaba
Input
输入一行最多不超过500 000 个最少1个小写字符.
Output
一个长度表示模版最小的长度.
Sample Input
ababbababbabababbabababbababbaba
Sample Output
8
想到fail树这题就很简单了,建起来就过了,感觉网上很多题解都很不错,讲的特别详细,我就偷个懒啦
至于为什么还要用链表,其实这是为了优化,并且这个优化非常好想到
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> G[500005];
char str[500005];
int len, fail[500005], son[500005], L[500005], R[500005];
void Sech(int u, int p)
{
int i, v;
if(u!=0)
{
R[L[u]] = R[u];
L[R[u]] = L[u];
len = max(len, R[u]-L[u]);
}
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
if(v==p)
continue;
Sech(v, p);
}
}
int main(void)
{
int n, i, j;
scanf("%s", str+1);
n = strlen(str+1);
i = 1, j = 0;
while(i<=n)
{
if(j==0 || str[i]==str[j])
{
i++, j++;
fail[i] = j;
}
else
j = fail[j];
}
for(i=1;i<=n;i++)
{
L[i] = i-1, R[i] = i+1;
fail[i] = fail[i+1]-1;
G[fail[i]].push_back(i);
}
i = n;
while(i)
{
son[fail[i]] = i;
i = fail[i];
}
for(i=0;i<=n;i=son[i])
{
len = 1;
Sech(i, son[i]);
if(len<=son[i])
break;
}
printf("%d\n", son[i]);
return 0;
}