「LOJ#10036」「一本通 2.1 练习 2」Seek the Name, Seek the Fame (Hash

题目描述

原题来自:POJ 2752

给定若干字符串(这些字符串总长 ≤4×105 le 4 imes 10^5 4×105),在每个字符串中求出所有既是前缀又是后缀的子串长度。

例如:ababcababababcabab,既是前缀又是后缀的:abababababcababababcababababcabab

输入格式

输入若干行,每行一个字符串。

输出格式

对于每个字符串,输出一行,包含若干个递增的整数,表示所有既是前缀又是后缀的子串长度。

样例

样例输入

ababcababababcabab
aaaaa

样例输出

2 4 9 18
1 2 3 4 5

题解

用哈希吖!

设长度为$n$。

$O(n)$扫一遍,得到Hash的前缀和,自然溢出。

再用$O(n)$预处理出位乘数的$1~n$次方,一样自然溢出。

最后用$O(n)$扫一遍,扫到每个点,就判断这个前缀与长度相同的后缀Hash值是否相同,判断$O(1)$。

总复杂度$O(n)$。

Hash真是该死的让人上瘾呢。

 1 编号     题目     状态     分数     总时间     内存     代码 / 答案文件     提交者     提交时间
 2 #229879     #10036. 「一本通 2.1 练习 2」Seek the Name, Seek the Fame    Accepted     100     237 ms     6908 KiB     C++ / 913 B     qwerta     2018-10-15 19:03:34
 3 
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 using namespace std;
 8 #define ULL unsigned long long
 9 char s[400003];
10 ULL h[400003];
11 const int p=33;//每位乘上的数(总感觉只乘26是活等着被卡
12 ULL ep[400003];
13 int main()
14 {
15     //freopen("a.in","r",stdin);
16     ios::sync_with_stdio(false);
17     cin.tie(false),cout.tie(false);
18     while(cin>>s)
19     {
20         int n=strlen(s)-1;
21         for(int i=0;i<=n;++i)
22         {
23           h[i]=h[i-1]*p+s[i]-'a'+1;//算Hash前缀和
24           //cout<<h[i]<<" ";
25         }
26         //cout<<endl;
27         ep[0]=1;
28         for(int i=1;i<=n;++i)
29         {
30           ep[i]=ep[i-1]*p;//算p的次方
31           //cout<<ep[i]<<" ";
32         }
33         //cout<<endl;
34         for(int i=0;i<=n;++i)
35         {
36             ULL ha,hb;//设ha为前缀,hb为后缀
37             ha=h[i];
38             hb=h[n]-h[n-i-1]*ep[i+1];
39             //cout<<ha<<" "<<hb<<endl;
40             if(ha==hb){cout<<i+1<<" ";}
41         }
42         cout<<endl;
43     }
44     return 0;
45 }
原文地址:https://www.cnblogs.com/qwerta/p/9813328.html