白兔的字符串
题目来源牛客网
题目描述
白兔有一个字符串T。白云有若干个字符串S1,S2…Sn。
白兔想知道,对于白云的每一个字符串,它有多少个子串是和T循环同构的。
提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。
所有字符都是小写英文字母
输入描述:
第一行一个字符串T(|T|<=10^6) 第二行一个正整数n (n<=1000) 接下来n行为S1~Sn (|S1|+|S2|+…+|Sn|<=10^7),max(|S1|,|S2|,|S3|,|S4|,..|Sn|)<=10^6
输出描述:
输出n行表示每个串的答案
abab 2 abababab ababcbaba
5 2
#include<iostream>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
using namespace std;
typedef unsigned long long ull;
const int N = 2e6 + 10;
//char s[N],str[N];
string s;
string str1,str2;
int t;
unordered_map<ull, int>xx; //map会超时。。。但是蓝桥杯不让用unordered_map
ull h[N], p[N];
ull find(int l, int r){
return h[r] - h[l - 1] * p[r - l + 1]; //求子串的哈希值
}
int main(){
int len1;
int ll;
cin >> s >> t;
str1 = " " + s + s; //这个题需要把T串变成两倍
/*
比如说abab 两倍之后 abababab
这个里面任何一个长度为四的字串都可以和abab同构
所以把长度扩大二倍后的字符串哈希求出来,
在和n组数据中长度为4的字符串进行比较九号
*/
len1 = str1.size();
p[0] = 1;
for(int i = 1; i <= len1; i++){
h[i] = h[i - 1] * 131 + str1[i];
p[i] = p[i - 1] * 131;
}
len1 = len1 / 2; //把长度变回去, 因为前面已经把哈希值求出来了
for(int i = 1; i <= len1; i++){ //把长度为len1的字符串哈希值都保存到map中
ull x = find(i, i + len1 - 1);
xx[x]++;
}
while(t--){
int ans = 0;
cin >> s;
str2 = " " + s;
int len2 = str2.size();
for(int i = 1; i < len2; i++){
h[i] = h[i - 1] * 131 + str2[i];
}
for(int i = 1; i < len2 - len1 + 1; i++){
ull x = find(i, i + len1 - 1); //把长度len1的进行匹配
if(xx[x]){
ans++;
}
}
cout << ans << endl;
}
return 0;
}