枚举每个位置,给每个串的前半部分一个哈希值,后半部分一个哈希值,若是它们均相等,则视为这两个串相似。
每次转移之后,排序一下就行了。
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; }
时间: 2024-10-14 12:20:57