//注意MAXN是最大不同的HASH个数,一般HASHN是MAXN的两倍左右,MAXLEN表示字符串的最大长度
//K表示正确率,越大正确率越高,当时也越费空间,费时间。
//使用前注意初始化hash_init();
//用法参考下面注释程序。
//HashNode里面可以储存很多信息,注意灵活使用。 内存如果可能溢出可修改使得内存减一半,但是注意乘法溢出。
#define HASHN 1000007
#define MAXN 500000
#define MAXLEN 500500
#define K 2
typedef unsigned long long ull;
typedef unsigned int ui;
struct HashNode
{
int next;
ull key[K];//关键点
}hashnode[MAXN];
const ull mod[3]={ 2147483647U, 2147483629U, 2147483587U };
const ull seed[3]={ 131U, 10007U, 4243U};
int hashpre[ HASHN ],hashcnt;
void hash_init()
{
hashcnt=0;
memset(hashpre,-1,sizeof(hashpre));
}
bool hash_find(ull key[K])
{
int hashkey=0;
for(int i=0;i<K;i++)
hashkey += (key[i])%HASHN;
hashkey %= HASHN;
ull nkey[K];
for(int p=hashpre[hashkey];p!=-1;p=hashnode[p].next)
{
for(int i=0;i<K;i++) nkey[i] = hashnode[p].key[i];
bool nsign=0;
for(int i=0;i<K;i++)
{
if(key[i] != nkey[i])
{
nsign=1;
break;
}
}
if(nsign==0) return true;
}
return false;
}
void hash_insert(ull key[K])
{
int hashkey=0;
for(int i=0;i<K;i++)
hashkey += (key[i])%HASHN;
hashkey %= HASHN;
if( hash_find(key) ) return ;//hash表中已经存在
//不存在使用头插入法,插入新节点。
for(int i=0;i<K;i++)
hashnode[hashcnt].key[i] = key[i];
hashnode[hashcnt].next = hashpre[hashkey];
hashpre[ hashkey ] = hashcnt++;
}
void hash_getkey(char *str,int len,ull key[K])
{
ull tmp=1;
for(int i=0;i<K;i++)
{
key[i] = 0;
tmp = 1;
for(int j=0;j<len;j++)
{
key[i] = ( key[i]+tmp*str[j] )%mod[i];
tmp *= seed[i];
tmp %= mod[i];
}
}
return ;
}
void hash_insert(char *str,int len)
{
ull key[K];
hash_getkey(str,len,key);
hash_insert(key);
}
bool hash_find(char *str,int len)
{
ull key[K];
hash_getkey(str,len,key);
return hash_find(key);
}
void hash_getpow(int len,ull hashpow[][MAXLEN])
{
ull tmp=1;
for(int i=0;i<K;i++)
{
tmp=1;
for(int j=0;j<len;j++)
{
hashpow[i][j] = tmp;
tmp *= seed[i];
tmp %= mod[i];
}
}
}
void hash_getsuffix(char *str,int len,ull hashsuf[][MAXLEN])
{
ull tmp=1;
for(int i=0;i<K;i++)
{
tmp=1;
for(int j=0;j<len;j++)
{
hashsuf[i][j] = (tmp*str[j])%mod[i];
tmp *= seed[i];
tmp %= mod[i];
}
hashsuf[i][len]=0;
for(int j=len-1;j>=0;j--)
{
hashsuf[i][j] += hashsuf[i][j+1];
if( hashsuf[i][j]>=mod[i] ) hashsuf[i][j] -= mod[i];
}
}
}
void hash_getprefix(char *str,int len,ull hashpref[][MAXLEN])
{
ull tmp=1;
for(int i=0;i<K;i++)
{
hashpref[i][0] = str[0];
tmp = seed[i];
for(int j=1;j<len;j++)
{
hashpref[i][j] = hashpref[i][j-1]+(tmp*str[j])%mod[i];
if( hashpref[i][j]>=mod[i] ) hashpref[i][j] -= mod[i];
tmp *= seed[i];
tmp %= mod[i];
}
}
}
/*
char str[1001000];
ull hashpow[K][MAXLEN],hashpref[K][MAXLEN],hashsuf[K][MAXLEN];
int main() {
int n,m;
scanf("%d%d",&n,&m);
hash_init();//第一步初始化
for(int i=0;i<n;i++)
{
scanf("%s",str);
int len=strlen(str);
hash_insert(str,len);//插入hash表
}
hash_getpow(MAXLEN, hashpow);//得到pow
for(int i=0;i<m;i++)
{
scanf("%s",str);
int len=strlen(str);
int flag=0;
hash_getprefix(str, len, hashpref);//得到前缀和
hash_getsuffix(str, len, hashsuf);//得到后缀和
//具体情况,具体操作。
for(int j=0;j<len;j++)
{
for(int k='a';k<='c';k++)
{
if(k==str[j]) continue;
ull key[K];
for(int p=0;p<K;p++)
{
key[p] =( (j>0?hashpref[p][j-1]:0) + hashpow[p][j]*k%mod[p]+hashsuf[p][j+1])%mod[p];
while(key[p]>=mod[p]) key[p] -= mod[p];
}
if( hash_find(key) )
{
flag=1;
break;
}
}
if(flag) break;
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
*/