CF 514C hash,字典树

题目链接:http://codeforces.com/problemset/problem/514/C


比较少碰到hash的题目,这个题目记录一下可以作为练手用。


题意:给你n个字符串作为母串,m个字符串作为字串,其中(0 <= n,m <= 3 * 10 ^ 5)。每个字串作为一个询问,每次询问你能否在母串中找出一个字符串,其中那个母串和这个字串有相同的长度,必有且仅有一个位置的字母是不相同的。


思路:因为字符串中只含有a,b,c,所以只要把a,b,c看作是1,2,3就可以了(不要看作0,1,2,不然aaaa跟aaa的hash值就相同了),然后对每一个母串进行hash,并将值放入set,其中mod要取大点。。。不然hash值重复的机率很高。然后对于每一个字串也进行同样的处理,并枚举子串上的每一位(a,b,c,不包括原子串在这个位置的字母),察看变化后的字串在set中有没有,有的话就说明存在一个母串跟子串只有1位不相同。


另外一种字典树的思路:一开始没看到要求母串跟子串长度要相同,结果写到一般的字典树就弃了。。。。。字典树的思路就更明显了,直接对所有母串进行建树,然后对于每个子串枚举每一位上的字母,看看字典树上有没有就行了。。。  复杂度应该也是Llogn,其中L为所有字串的长度,logn为每次找字典树的复杂度。。。。


hash代码:

#include 
#include 
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
const int maxn = 100005;
const ll mod = 1e15 + 7;//这个大一点就行了,不固定,如果大一点的都wa了就是rp不行
set se;

string s;
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++)
	{
		cin>>s;
		int len  = s.length();
		ll sum = 0;
		for(int i = 0;i < len;i++)
			sum = (sum * 4 + s[i] - 'a' + 1) % mod;
		se.insert(sum);
	}
	int len;
	string ss;
	while(m--)
	{
		cin>>s;
		len = s.length();
		int ok = 0;
		ll sum = 0;
		ll temp;
		for(int i = 0;i < len;i++)
			sum = (sum * 4 + s[i] - 'a' + 1) % mod;
		ll cheng = 1;
		for(int i = len - 1;i >= 0;i--)
		{
			temp = (sum - (s[i] - 'a' + 1) * cheng) % mod;
			temp += mod;
			temp %= mod;
			for(int j = 1;j < 4;j++)
				if((j + 'a' - 1 != s[i]) && se.find((temp + j * cheng) % mod) != se.end())
				{
					ok = 1;break;
				}
			if(ok)break;
			cheng = cheng * 4 % mod;
		}
		if(ok)puts("YES");else puts("NO");
	}
}



字典树代码:

#include 
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
const int maxn = 100005;

struct ppp
{
	int nex[3];
	void make()
	{
		mem(nex,-1);
	}
}node[maxn * 40];
int tole,len;
string s;
void build(int pos,int now)
{
	if(pos >= len)return;
	int v = s[pos] - 'a';
	if(node[now].nex[v] == -1)
	{
		node[now].nex[v] = ++tole;
		node[tole].make();
		build(pos + 1,tole);
	}
	else 
		build(pos + 1,node[now].nex[v]);
}
int ok;
void dfs(int pos,int now,int f)
{
	if(pos == len){
		int ff = 1;
		for(int i = 0;i < 3;i++)
			if(node[now].nex[i] > 0)
				ff = 0;
		if(f && ff)
			ok = 1;
		return;
	}
	int v = s[pos] - 'a';
	int gc;
	gc = node[now].nex[v];
	if(gc != -1)
		dfs(pos + 1,node[now].nex[v],f);
	if(!f)
	for(int i = 1;i <= 2;i++)
		{
			int vv = v + i;
			if(vv >= 3)vv -= 3;
			gc = node[now].nex[vv];
			if(gc != -1)
				dfs(pos + 1,node[now].nex[vv],1);
		}
}

int main()
{
	tole = 0;
	node[tole].make();
	int n,m;
	scanf("%d%d",&n,&m); 
	while(n--)
	{
		cin>>s;
		len = s.length();
		build(0,0);
	}
	while(m--)
	{
		cin>>s;
		len = s.length();
		ok = 0;
		dfs(0,0,0);
		if(ok)puts("YES");
		else puts("NO");
	}
}

发布了50 篇原创文章 · 获赞 3 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章