題目鏈接: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");
}
}