题意:给你一个串,让你找出AABB型的子串有多少种,A可以为一个字符串,但A≠B
思路:我觉得这篇讲的很清楚(传送门),我觉得这个题只有在lcp的那个地方不是很容易想到,从来没想过lcp还可以这么用,代码是搬运claris小姐姐的
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=80005; char s[maxn]; int T,n,Log[maxn],l,r,f[maxn],g[maxn]; LL ans; /** 在使用后缀数组时要先进行倍增预处理,调用init_suffix s为字符串 sa为后缀数组,记录排序后的后缀数组的位置 rk为记录以i开始的后缀在后缀数组中的位置 height为高度数组,表示排序后相邻的两个后缀的公共前缀 lcp函数可以查两个位置的lcp公共长度 */ void init_suffix() { for(int i=2;i<maxn;i++)Log[i]=Log[i>>1]+1; } struct SuffixArray { char s[maxn]; int sa[maxn],rk[maxn],height[maxn],tmp[maxn],cnt[maxn],f[15][maxn],len; inline void init() { for(int i=0;i<len*2+5;i++)s[i]=0; } inline void suffix(int m) { int i,j,k,len1=len+1;; for(i=0;i<len1*2+5;i++)rk[i]=sa[i]=height[i]=tmp[i]=0; for(i=0;i<m;i++)cnt[i]=0; for(i=0;i<len1;i++)cnt[rk[i]=s[i]]++; for(i=1;i<m;i++)cnt[i]+=cnt[i-1]; for(i=0;i<len1;i++)sa[--cnt[rk[i]]]=i; for(k=1;k<=len1;k<<=1){ for(i=0;i<len1;i++){ j=sa[i]-k; if(j<0)j+=len1; tmp[cnt[rk[j]]++]=j; } sa[tmp[cnt[0]=0]]=j=0; for(i=1;i<len1;i++){ if(rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k])cnt[++j]=i; sa[tmp[i]]=j; } memcpy(rk,sa,len1*sizeof(int)); memcpy(sa,tmp,len1*sizeof(int)); if(j>=len1-1)break; } for(j=rk[height[i=k=0]=0];i<len1-1;i++,k++){ while(~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rk[sa[j]+1]; } } inline void build() { int i,j; for(i=1;i<=len;i++)f[0][i]=height[i]; for(j=1;j<15;j++){ for(i=1;i+(1<<j-1)<=n;i++){ f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]); } } } inline int ask(int x,int y) { int k=Log[y-x+1]; return min(f[k][x],f[k][y-(1<<k)+1]); } inline int lcp(int x,int y) { x=rk[x],y=rk[y]; if(x>y)swap(x,y); return ask(x+1,y); } }A,B; inline int lcp(int x,int y){return A.lcp(x-1,y-1);} inline int lcs(int x,int y){return B.lcp(n-x,n-y);} int main() { init_suffix(); scanf("%d",&T); while(T--){ scanf("%s",s); n=strlen(s); A.len=B.len=n; A.init();B.init(); for(int i=0;i<n;i++)A.s[i]=B.s[n-i-1]=s[i]; A.suffix(128); A.build(); B.suffix(128); B.build(); for(int i=1;i<=n;i++)f[i]=g[i]=0; for(int i=1;i+i<=n;i++){ for(int j=i+i;j<=n;j+=i){ if(s[j-1]==s[j-i-1]){ l=j-lcs(j,j-i)+1,r=j+lcp(j,j-i)-1; l=max(l+i-1,j),r=min(r,j+i-1); if(l<=r){ f[l]++,f[r+1]--; g[l-i-i+1]++,g[r+1-i-i+1]--; } } } } for(int i=1;i<=n;i++)f[i]+=f[i-1],g[i]+=g[i-1]; ans=0; for(int i=1;i<n;i++)ans+=f[i]*g[i+1]; printf("%lld ",ans); } return 0; }