题目链接: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");
}
}