牛客练习->字符串Hash->白兔的字符串(哈希表)

题目链接

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

白兔有一个字符串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

判断是否与主串循环同构,直接在主串后加上一段相同的,如abcde->abcdeabcde

用power[i]表示Base^i,这时的哈希函数与POJ3461 && LOJ#10033 Oulipo(字符串HASH)类似

令Hash[i]表示字符串s_1s_2\cdots s_i的哈希值,则字符串s_ls_{l+1}\cdots s_r的哈希值为Hash[r]-Hash[l-1]*power[r-l+1]

以10进制数字为例,123456,Hash[1]=1,Hash[2]=12,Hash[3]=123,Hash[4]=1234,Hash[5]=12345,Hash[6]=123456,
3456(l=3,r=6)=Hash[6]-Hash[2]*power[6-2+1]=123456-12*10000=3456。

AC代码:

//CSDN博客:https://blog.csdn.net/qq_40889820
#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<string>
#include<cstring>
#include<iomanip>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<map>
#include<set>
#define mem(a,b) memset(a,b,sizeof(a))
#define random(a,b) (rand()%(b-a+1)+a)
#define ull unsigned long long
#define e 2.71828182
#define Pi 3.141592654

using namespace std;
const int MAXN=2e6+10;
const int Base=1e7+7;
const int mod=14937;
ull power[MAXN],htmp;
char T[MAXN],S[MAXN];
int lenT,lenS;
ull has[MAXN]; 
vector<ull> HashTable[mod];//邻接表 
int n;
void add_edge(ull h)
{
	int pos=h%mod;
	HashTable[pos].push_back(h);
}
int find(ull h)
{
	int pos=h%mod;
	for(int i=0;i<HashTable[pos].size();++i)
	{
		if(HashTable[pos][i]==h) return 1;
	}
	return 0;
}
inline void initial_hash()
{
	power[0]=1;
	for(int i=1;i<=lenT;++i) power[i]=power[i-1]*Base;
	
	for(int i=1;i<=lenT+lenT;++i)
	{
		has[i]=has[i-1]*Base+T[i];
		if(i>=lenT)
		{
			T[i+1]=T[i-lenT+1];
			htmp=has[i]-has[i-lenT]*power[lenT];
			add_edge(htmp);
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>(T+1);
	lenT=strlen(T+1);
	initial_hash();
	cin>>n;
	while(n--)
	{
		cin>>(S+1);
		lenS=strlen(S+1);
		int ans=0;
		
		for(int i=1;i<=lenS;++i)
		{
			has[i]=has[i-1]*Base+S[i];
			if(i>=lenT)
			{
				htmp=has[i]-has[i-lenT]*power[lenT];
				ans+=find(htmp);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

 

参考:
https://blog.csdn.net/albertluf/article/details/79522958

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值