循环同构字符串 字符串哈希
题目
白兔的字符串(https://ac.nowcoder.com/acm/problem/15253)
题目描述
白兔有一个字符串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行表示每个串的答案
示例1
输入
abab
2
abababab
ababcbaba
输出
5
2
思路
循环同构,我们吧T环拆链,然后保存所有的循环同构字符串字符串哈希就可以了。
对于查询查询长度为|T|的哈希值的是否存在就可以了。
坑点:要自然溢出才能A。
#include <bits/stdc++.h>
#define uLL unsigned long long
#define LL long long
using namespace std;
const int maxn=2000005;
struct Hash_char {
uLL base=131;
uLL p[maxn], g[maxn];
void getp() {
p[0]=1;
for(int i=1; i<maxn; i++) {
p[i]=p[i-1]*base;
}
}
uLL Hash(char s[]) {
int len=strlen(s+1);
g[0]=0, g[1]=s[1];
for(int i=2; i<=len; i++) {
g[i]=(g[i-1]*base+s[i]);
}
return g[len];
}
uLL getLR(int l, int r) { //得到s[l]-s[r]的hash值
uLL ans=(g[r]-g[l-1]*p[r-l+1]);
return ans;
}
} hc, hd;
struct HashMap { //拉链法hash表
static const int MXSZ = 1e7 + 100; //元素总数 查询也会创建元素 能开大就开大
static const int MOD = 1e6 + 3; //1e3+9 1e4+7 1e6+3 1e7+19 1e8+7
struct node {
uLL key, val;
int nxt;
} elem[MXSZ];
int head[MOD], tot;
void init() { //注意初始化!!!
tot = 0;
memset(head, -1, sizeof(head));
}
bool count(uLL key){
int k = key % MOD;
for (int i = head[k]; ~i; i = elem[i].nxt)
if (elem[i].key == key)
return 1;
return 0;
}
uLL& operator [] (uLL key) {
int k = key % MOD; //取模位置
for (int i = head[k]; ~i; i = elem[i].nxt)
if (elem[i].key == key) //key相等
return elem[i].val; //返回val引用
elem[tot].key = key, elem[tot].nxt = head[k], head[k] = tot; //新建项 将原有的接在当前后并记录当前
return elem[tot++].val = 0; //清空值并返回引用
}
}mp;
char s[maxn];
int main() {
hc.getp(); hd.getp(); mp.init();
scanf("%s", s+1);
int N=strlen(s+1);
for(int i=1; i<=N; i++) s[N+i]=s[i];
hc.Hash(s);
for(int i=1; i<=N; i++){
mp[hc.getLR(i, i+N-1)]=1;
}
int t;
scanf("%d", &t);
while(t--) {
scanf("%s", s+1);
int len=strlen(s+1);
if(len<N){
printf("0\n"); continue;
}
hd.Hash(s);
int ans=0;
for(int i=1; i<=len-N+1; i++){
uLL res=hd.getLR(i, i+N-1);
if(mp.count(res)){
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}