题目描述
给定若干只含小写字母的字符串(这些字符串总长≤400000),在每个字符串中求出所有既是前缀又是后缀的子串长度。
例如:ababcababababcabab,既是前缀又是后缀的子串:ab,abab,ababcabab,ababcababababcabab。
输入格式
输入若干行,每行一个字符串。
输出格式
对于每个字符串,输出一行,包含若干个递增的整数,表示所有既是前缀又是后缀的子串长度。
样例输入
ababcababababcabab
aaaaa
alala
nucacm
样例输出
2 4 9 18
1 2 3 4 5
1 3 5
6
读题
过于简单,证明略
代码
#include<bits/stdc++.h>
using namespace std;
const int b=131,M=1e6;
#define _for(i,a,b) for (int i=(a);i<=(b);i++)
char s[M];
int h[M],p[M],n;
bool init(){
if (scanf("%s",s+1)!=1) return 0;
n=strlen(s+1);
_for(i,1,n)
h[i]=h[i-1]*b+(s[i]-'A'+1);
return true;
}
int hs(int l,int r,int len){
return h[r]-h[l-1]*p[len];
}
int main() {
p[0]=1;
_for (i,1,M) p[i]=p[i-1]*b;
while (init()){
_for (i,1,n){
if (hs(1,i,i)==hs(n-i+1,n,i)){
cout<<i<<' ';
}
}
cout<<endl;
}
return 0;
}
分析
与Power Strings相同,都在找子串。
笔者在此想分为两部分来谈论,具体分为hs
与init
init
init()
函数的作用是对字符串进行初始化操作,并计算字符串的前缀哈希值。
-
使用
scanf("%s", s+1)
从输入中读取一个字符串并存储到字符数组s
中。这里将读取的字符串存储在s
的下标为 1 的位置开始,留出第 0 位作为占位符。(想一想,为什么) -
获取字符串的长度
n
,即通过strlen(s+1)
来计算s
的有效长度。 -
使用
_for
循环(循环宏)遍历字符串的每个字符,从 1 到n
,计算字符的哈希值,并存储在数组h
中。其中,数组h
的每个元素表示对应位置之前的子串的哈希值,计算方式为:h[i] = h[i-1] * b + (s[i] - 'A' + 1)
,其中b
是常量
至此,init()
函数完成对输入的字符串进行初始化,并计算出字符串的前缀哈希值,以供后续的处理和比较使用。
hs
获取子串的hash值,具体说使用前缀哈希值数组 h 计算从起点 l 开始,长度为 len 的子串的哈希值,当然,要给出重点r。