uoj219 优秀的拆分 字符串
题意:找出字符串之中所有符合$AABB$形式子串的划分方式。
这道题正解是$SA$……我不会……
然而二分+$Hash$可过……可过……
首先我们枚举每一个$A$的长度,然后我们二分长度搞出来各个位置与上一段的$LCS$,$LCP$长度。随后我们将$LCS$起点向左,$LCP$终点向右移动长度个字符,如果二者仍然没有相遇,差分相加。最后相邻的统计个数即可。
(语言说不太明白,还是上代码吧)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=50005,base=31; 7 const int mod=998244353; 8 char s[maxn]; 9 long long hash[maxn],t[maxn],u[maxn],v[maxn],ans; 10 inline long long gethash(int l,int r) 11 { 12 return ((hash[l]-hash[r]*t[r-l])%mod+mod)%mod; 13 } 14 int haha() 15 { 16 int T;scanf("%d",&T); 17 t[0]=1;for(int i=1;i<=30000;i++)t[i]=t[i-1]*base%mod; 18 while(T--) 19 { 20 scanf("%s",s+1);int n=strlen(s+1); 21 memset(u,0,sizeof(u)),memset(v,0,sizeof(v)); 22 hash[n+1]=0; 23 for(int i=n;i;i--)hash[i]=(hash[i+1]*base+s[i]-'0'+1)%mod; 24 for(int len=1;(len<<1)<=n;len++) 25 for(int i=(len<<1);i<=n;i+=len) 26 { 27 if(s[i]!=s[i-len])continue; 28 int l=1,r=len,last=i-len,pos=0; 29 while(l<=r) 30 { 31 int mid=(l+r)>>1; 32 if(gethash(last-mid+1,last+1)==gethash(i-mid+1,i+1))l=mid+1,pos=mid; 33 else r=mid-1; 34 } 35 int head=i-pos+1; 36 l=1,r=len,pos=0; 37 while(l<=r) 38 { 39 int mid=(l+r)>>1; 40 if(gethash(last,last+mid)==gethash(i,i+mid))l=mid+1,pos=mid; 41 else r=mid-1; 42 } 43 int tail=i+pos-1; 44 head=max(head+len-1,i),tail=min(tail,i+len-1); 45 if(head<=tail) 46 { 47 u[head-(len<<1)+1]++,u[tail+1-(len<<1)+1]--; 48 v[head]++,v[tail+1]--; 49 } 50 } 51 ans=0; 52 for(int i=1;i<=n;i++)u[i]+=u[i-1],v[i]+=v[i-1]; 53 for(int i=1;i<n;i++)ans+=v[i]*u[i+1]; 54 printf("%lld\n",ans); 55 } 56 } 57 int sb=haha(); 58 int main(){;}
至于$SA$写法……以后再回来填吧……(有生之年系列)
只要是活着的东西,就算是神我也杀给你看。