首页 > 代码库 > 【字符串哈希】bzoj3555 [Ctsc2014]企鹅QQ

【字符串哈希】bzoj3555 [Ctsc2014]企鹅QQ

枚举每个位置,给每个串的前半部分一个哈希值,后半部分一个哈希值,若是它们均相等,则视为这两个串相似。

每次转移之后,排序一下就行了。

O(L*n*log(n))。

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>using namespace std;typedef unsigned long long ull;struct HASH{ull l,r;}hss[30001],tmp[30001];bool operator < (const HASH &a,const HASH &b){return a.l!=b.l ? a.l<b.l : a.r<b.r;}bool operator != (const HASH &a,const HASH &b){return (a.l!=b.l||a.r!=b.r);}ull seed,seeds[201];int ord[301],n,m,ans;char s[30001][201];void init(){	if(seed==2) ord[‘0‘]=1,ord[‘1‘]=2;	else	  {	  	int en=0;	  	for(char c=‘A‘;c<=‘Z‘;++c) ord[c]=++en;	  	for(char c=‘a‘;c<=‘z‘;++c) ord[c]=++en;	  	for(char c=‘0‘;c<=‘9‘;++c) ord[c]=++en;	  	ord[‘_‘]=++en; ord[‘@‘]=++en;	  }	++seed; seeds[0]=1;	for(int i=1;i<=m;++i)	  seeds[i]=seeds[i-1]*seed;}int main(){	scanf("%d%d",&n,&m); cin>>seed;	init();	for(int i=1;i<=n;++i)	  {	  	scanf("%s",s[i]);	  	for(int j=1;j<m;++j)	  	  hss[i].r=hss[i].r*seed+(ull)ord[s[i][j]];	  }	memcpy(tmp,hss,(n+1)*sizeof(HASH));	for(int i=1;i<=m;++i)	  {	  	int head;	  	sort(hss+1,hss+n+1);	  	for(int j=1;j<=n;++j)	  	  {	  	  	tmp[j].l=tmp[j].l*seed+(ull)ord[s[j][i-1]];	  	  	tmp[j].r-=seeds[m-1-i]*(ull)ord[s[j][i]];	  	  	if(j==1 || hss[j]!=hss[j-1]) head=j;	  	  	if(j==n || hss[j]!=hss[j+1]) ans+=(((j-head+1)*(j-head))>>1);	  	  }	  	memcpy(hss,tmp,(n+1)*sizeof(HASH));	  }	printf("%d\n",ans);	return 0;}

【字符串哈希】bzoj3555 [Ctsc2014]企鹅QQ