题目描述
输入描述:
输出描述:
示例1
输入
3
ab
ba
aba
输出
29
说明
题目大意
给定n个字符串,求所有字符串前缀与后缀相等的个数与前后缀的长度的平方的和。如样例,匹配长度为1,2,3的分别有4,4,1个,所以答案为
4 *1 ^2 +4 *2 ^2 +1 *3 ^2=29
分析
许多dalao们看到这题就会想到用map把所有的后缀(前缀)映射进去,然后对于每个前缀(后缀),就可以直接查找下就可以了。但是,map是pair和set合用,这全搞在一起是很慢的,看到1e6的长度,就是TLE。所以要找一个更加高深的算法。
HASH
哈希是字符串题目中的bug方法,基本上能水过去,实在不行还能骗不少分。本题中可以把后缀(前缀)的哈希值求出,然后将前缀(后缀)的哈希值与之比较,就能比较快捷地求出匹配了。但是哈希的进制搞成多少好呢?一般我们都是取一个素数进制,冲突的概率比较小。然而,本题有1e6的长度,以233进制的哈希为例,搞不好就是2331e6,炸上天。因此需要一个mod。但是这个mod之后,它也有概率会冲突。这就是看运气了。有一下3种比较好的解决这个办法。(后文采取第二种)
1、用大素数取模,这种冲突产生的概率就十分小了。
2、用unsigned long long,直接省略超出部分,概率小且写代码方便。
3、双哈希,这种方式就是取两种进制,然后都取一个mod,如果这都能冲突,那真可以买彩票了,唯一不足就是有点烦,蒟蒻不太喜欢这种写法。
以下是图示,是哈希的原理,即为进制转换,转换成233进制之类的。第一位的数值是2330 *当前位,以此类推。
具体代码见下。
void puthash(string a){
int len=a.size();
ull sum=0,p=1;//用ull解决冲突
for(int i=len-1;i>=0;i--){
sum+=(a[i]-'a'+1)*p;
p*=233;
mp[sum]++;