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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章