Enumerate each location, give the first half of each string a hash value, a hash value for the second half, and, if they are equal, the two strings are similar.
After each transfer, sort it out.
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;}
String hash bzoj3555 [Ctsc2014] Penguin QQ