牛客:D白兔的字符串

题目链接:https://ac.nowcoder.com/acm/contest/73/D?&headNav=www

题目描述

白兔有一个字符串T。白云有若干个字符串S1,S2…Sn。

白兔想知道,对于白云的每一个字符串,它有多少个子串是和T循环同构的。

提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。

所有字符都是小写英文字母

输入描述:

第一行一个字符串T(|T|<=10^6)
第二行一个正整数n (n<=1000)
接下来n行为S1~Sn (|S1|+|S2|+…+|Sn|<=107),max(|S1|,|S2|,|S3|,|S4|,…|Sn|)<=106

输出描述:

输出n行表示每个串的答案

示例1

abab
2
abababab
ababcbaba

输出

5
2

思路

用字符串hash函数把字符串T中的每一个长度都为strlen(T)的循环子串转换成关键字存储起来,然后对于每一个样例,查找其中长度为strlen(T)的子字符串是否在其中即可。。
会用到的hash函数
hash[n]=hash[n-1]*base+ch;
在[l,r]之间的字符串的哈希值是
hash[r]-hash[l-1]*h[r-l+1];

代码

#include
#include
#include
#include

using namespace std;
typedef unsigned long long ull;
const int maxn = 2e6 + 7;
const int base = 131;
const int mod = 1000007;
char str[maxn];
ull has[maxn], h[maxn];
int head[mod];
int total = 0;

struct  node
{
     
	ull key;
	int next;
}rode[maxn];

void add(ull x)
{
     
	int pos = x % mod;
	rode[total].key = x;
	rode[total].next = head[pos];
	head[pos] = total++;
}

int find(ull x)
{
     
	int pos = x % mod;
	for (int i = head[pos]; i != -1; i = rode[i].next)
	{
     
		if (rode[i].key == x)
			return 1;
	}
	return 0;
}

int main()
{
     
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> str + 1;
	int L = strlen(str + 1);
	memset(head, -1, sizeof(head));
	for (int i = 1; i <= L; i++)
	{
     
		str[i + L] = str[i];
	}
	h[0] = 1;
	for (int i = 1; i <= L; i++)
	{
     
		h[i] = h[i - 1] * base;
	}
	has[0] = 0;
	for (int i = 1; i <= 2 * L; i++)
	{
     
		has[i] = has[i - 1] * base + str[i];
		if (i >= L)
		{
     
			add(has[i] - has[i - L] * h[L]);
		}
	}
	int T;
	cin >> T;
	while (T--)
	{
     
		int ans = 0;
		cin >> str + 1;
		int l = strlen(str + 1);
		for (int i = 1; i <= l; i++)
		{
     
			has[i] = has[i - 1] * base + str[i];
			if (i >= L)
			{
     
				ans += find(has[i] - has[i - L] * h[L]);
			}
		}
		cout << ans << endl;
	}
	return 0;
}

你可能感兴趣的:(字符串,hash)