luogu1117 优秀的拆分 (后缀数组)
考虑分别计算每个位置作为AA的末尾或者BB的开头的个数 最后乘一乘就是答案
据说是套路的计算AA的方法:
首先枚举A的长度L,然后每L个字符当做一个关键点,这样的话,一个AA包含且只包含相邻两个关键点(记为a,b),而且满足lcp(a,b)+lcs(a,b)-1>=L 手画一下就能看出来
于是SA搞lcp 倒过来再SA搞lcs 最后差分一下统计答案即可
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 #define MP make_pair 5 using namespace std; 6 typedef long long ll; 7 const int maxn=3e4+10; 8 9 inline char gc(){ 10 return getchar(); 11 static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf; 12 return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++; 13 } 14 inline ll rd(){ 15 ll x=0;char c=gc();bool neg=0; 16 while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();} 17 while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc(); 18 return neg?(~x+1):x; 19 } 20 21 char str[maxn]; 22 int lg2[maxn],N; 23 24 struct SA{ 25 int cnt[maxn*2],tmp[maxn*2],rnk[maxn*2],sa[maxn*2],hei[maxn]; 26 int st[maxn][20],n; 27 28 inline void build(char *s){ 29 int i,j=0,k,m=26; 30 CLR(cnt,0);CLR(rnk,0); 31 for(i=1;i<=n;i++) cnt[s[i]-'a']=1; 32 for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; 33 for(i=1;i<=n;i++) rnk[i]=cnt[s[i]-'a']; 34 for(k=1;j!=n;k<<=1){ 35 CLR(cnt,0); 36 for(i=1;i<=n;i++) cnt[rnk[i+k]]++; 37 for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; 38 for(i=n;i;i--) tmp[cnt[rnk[i+k]]--]=i; 39 CLR(cnt,0); 40 for(i=1;i<=n;i++) cnt[rnk[i]]++; 41 for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; 42 for(i=n;i;i--) sa[cnt[rnk[tmp[i]]]--]=tmp[i]; 43 memcpy(tmp,rnk,sizeof(rnk)); 44 rnk[sa[1]]=j=1; 45 for(i=2;i<=n;i++){ 46 if(tmp[sa[i]]!=tmp[sa[i-1]]||tmp[sa[i]+k]!=tmp[sa[i-1]+k]) j++; 47 rnk[sa[i]]=j; 48 }m=j; 49 } 50 51 hei[1]=0; 52 for(i=1,j=0;i<=n;i++){ 53 if(rnk[i]==1) continue; 54 if(j) j--; 55 int x=sa[rnk[i]-1]; 56 while(i+j<=n&&x+j<=n&&s[i+j]==s[x+j]) j++; 57 hei[rnk[i]]=j; 58 } 59 // for(i=1;i<=n;i++) printf("hei:%d %d ; rnk:%d ; sa:%d \n",i,hei[i],rnk[i],sa[i]); 60 for(i=n;i;i--){ 61 st[i][0]=hei[i]; 62 for(j=1;i+(1<<j)-1<=n;j++){ 63 st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]); 64 } 65 } 66 } 67 68 inline int query(int x,int y){ //x,y:pos 69 if(x==y) return n-y+1; 70 int l=min(rnk[x],rnk[y])+1,r=max(rnk[x],rnk[y]); 71 // printf("~%d %d\n",l,r); 72 int k=lg2[r-l+1]; 73 return min(st[l][k],st[r-(1<<k)+1][k]); 74 } 75 }fw,bw; 76 77 int end[maxn],beg[maxn]; 78 79 int main(){ 80 //freopen("","r",stdin); 81 int i,j,k; 82 for(i=2;i<=30000;i++) lg2[i]=lg2[i>>1]+1; 83 for(int T=rd();T;T--){ 84 scanf("%s",str+1);N=strlen(str+1); 85 fw.n=bw.n=N; 86 fw.build(str); 87 reverse(str+1,str+N+1); 88 bw.build(str); 89 CLR(end,0);CLR(beg,0); 90 for(int l=1;l<=N;l++){ 91 i=l+1; 92 for(;i<=N;i+=l){ 93 int lcp=min(l,fw.query(i-l,i)),lcs=min(l,bw.query(N-i+1,N-(i-l)+1)); 94 // printf("!%d %d %d %d\n",i,i-l,lcp,lcs); 95 if(lcp+lcs-1>=l){ 96 end[i+l-lcs]++,end[i+lcp]--; 97 // printf("add A:%d %d\n",i+l-lcs,i+lcp-1); 98 beg[i-l-lcs+1]++,beg[i-2*l+lcp+1]--; 99 // printf("add B:%d %d\n",i-l-lcs+1,i-2*l+lcp); 100 } 101 } 102 } 103 for(i=1;i<=N;i++) end[i]+=end[i-1],beg[i]+=beg[i-1]; 104 ll ans=0; 105 for(i=1;i<N;i++){ 106 ans+=end[i]*beg[i+1]; 107 } 108 printf("%lld\n",ans); 109 } 110 return 0; 111 }