解题思路:按照字符串哈希的一般思路就是把求出T的哈希值和S1,S2……每个字符串的前缀预处理并保存起来,然后将每个字符串的前缀哈希值和T的哈希值比较是否相同,相同则同构。但本题不同的是判断字符串是否同构(题目提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。),也就是说对于样例中的T:abab而言,abab、baba、abab、baba都与它(T)同构。所以我们需要预处理出来与T的同构的字符串的哈希值并保存。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 2e6 + 11, P = 131; //char型字符串开空间时至少等于字符串长度+1(字符串末尾有'\0')
ULL h[N], p[N];
char str[N], s[N];
int n;
vector<ULL> V;
ULL get(int l, int r)
{
return h[r] - h[l-1] * p[r-l+1];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> str + 1;
int len = strlen(str+1);
for(int i = 1; i <= len; i ++)
str[len + i] = str[i]; //str后面再接一个str,以便后面求它的同构字符串
p[0] = 1;
for(int i = 1; i <= N; i ++)
p[i] = p[i-1] * P;
for(int i = 1; i <= len*2; i ++)
h[i] = h[i-1] * P + str[i];
for(int i = 1; i <= len; i ++)
V.push_back(get(i, i+len-1)); //将str的所有同构字符串的哈希值存入mp
sort(V.begin(), V.end());
cin >> n;
while(n -- )
{
int ans = 0;
cin >> s + 1;
memset(h, 0, sizeof h);
int lens = strlen(s+1);
for(int i = 1; i <= lens; i ++)
h[i] = h[i-1] * P + s[i];
for(int i = 1; i <= lens - len + 1; i ++)
{
ULL x = get(i, i+len-1);
int pos = lower_bound(V.begin(), V.end(), x) - V.begin(); //得到第一个等于或大于x(s的长度为len的子串哈希值)
if(pos != V.size()) //如果返回的pos不是V.size(),就可能是str的同构串
{
if(V[pos] == x) ans ++;
}
}
cout << ans << endl;
}
return 0;
}
今日做题心得:太依赖题解,思考题目的时候一遇到卡的地方就走神,不专心,不仔细分析题目,总是着急说自己知识欠缺所以不会做很正常,等看完题解后又后悔自己怎么不再认真思考思考。