Seek the Name, Seek the Fame (字符串hash)
poj-2752
题目描述
给定若干只含小写字母的字符串(这些字符串总长≤400000),在每个字符串中求出所有既是前缀又是后缀的子串长度。
例如:ababcababababcabab,既是前缀又是后缀的子串:ab,abab,ababcabab,ababcababababcabab。
输入格式
输入若干行,每行一个字符串。
输出格式
对于每个字符串,输出一行,包含若干个递增的整数,表示所有既是前缀又是后缀的子串长度。
样例输入
ababcababababcabab
aaaaa
alala
nucacm
样例输出
2 4 9 18
1 2 3 4 5
1 3 5
6
思路
直接套字符串hash。
计算原字符串的hash。然后枚举长度,判断 前 len 的长度的字符串hash和后 len 长度的字符串hash是否相同。相同就输出len.
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 1000090
#define base 161
typedef unsigned long long ull;
ull p[N], hs[N];
char str[N];
ull gethash(int l, int r)
{
return hs[r] - p[r - l + 1] * hs[l - 1];
}
void cal()
{
hs[0] = 0;
int len = strlen(str + 1);
for (int i = 1; i <= len; i++)
hs[i] = hs[i - 1] * base + str[i];
}
void slove()
{
cal();
int len = strlen(str + 1);
int res = 0, f = 0;
for (int i = 1; i <= len; i++)
{
if (gethash(1, 1 + i - 1) == gethash(len - i + 1, len))
if (!f)
{
cout << i;
f = 1;
}
else
cout << " " << i;
}
cout << endl;
}
int main()
{
p[0] = 1;
for (int i = 1; i <= N; i++)
p[i] = p[i - 1] * base;
while (scanf("%s", str + 1) != EOF)
{
slove();
}
}