【字符串哈希】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;
}
posted @ 2014-12-28 14:31  AutSky_JadeK  阅读(242)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト