http://www.lydsy.com/JudgeOnline/problem.php?id=2534
给定字符串S,求形式为ABA的子串个数,其中B的长度为L。
考虑A的两个起始位置x,y(x<y),应该满足如下两个条件:
1.y>x+L
2.LCP(x,y)≥y-x-L
我们按height从大到小枚举,这样LCP就是变成了当前的height,将两个集合统计答案并合并。统计答案时枚举size较小的集合内的点作为x或y即可。可以用平衡树或者主席树来维护。
#include<bits/stdc++.h> using namespace std; const int maxn=50015; typedef long long int64; typedef pair<int,int> PII; int n,l,cnt,q[maxn]; int64 ans;char s[maxn]; struct Tsplay{ int tot; static const int maxnode=1000015; struct Tnode{ Tnode *f,*c[2];int n,siz,val; void update(){siz=c[0]->siz+c[1]->siz+1;} void link(Tnode *newf,int newn){n=newn;f=newf;if (n!=2) f->c[n]=this;} }T[maxnode],*root[maxn],*null; void clear(){ tot=0;null=T;null->c[0]=null->c[1]=null;null->siz=0; for (int i=1;i<=n;++i) root[i]=null; } Tnode *newnode(int v){ Tnode *cur=T+(++tot); cur->f=cur->c[0]=cur->c[1]=null; cur->n=2;cur->val=v;cur->siz=1; return cur; } void rotate(Tnode *x){ Tnode *y=x->f,*z=y->f;int nx=x->n,ny=y->n; x->link(z,ny);x->c[!nx]->link(y,nx);y->link(x,!nx); y->update(); } void splay(int p,Tnode *x){ while (x->n!=2){ x->n==x->f->n?rotate(x->f):rotate(x); if (x->n!=2) rotate(x); } root[p]=x;x->update(); } void insert(int p,int val){ Tnode *x=root[p]; if (x==null){root[p]=newnode(val);return;} while (1){ if (val<x->val){ if (x->c[0]==null){x->c[0]=newnode(val);x->c[0]->link(x,0);splay(p,x->c[0]);return;} else x=x->c[0]; } else{ if (x->c[1]==null){x->c[1]=newnode(val);x->c[1]->link(x,1);splay(p,x->c[1]);return;} else x=x->c[1]; } } } int greater(int p,int v){ Tnode *res=null,*x=root[p]; while (x!=null){ if (x->val>v){res=x;x=x->c[0];} else x=x->c[1]; } if (res==null) return 0; else{splay(p,res);return res->c[1]->siz+1;} } int less(int p,int v){ Tnode *res=null,*x=root[p]; while (x!=null){ if (x->val<v){res=x;x=x->c[1];} else x=x->c[0]; } if (res==null) return 0; else{splay(p,res);return res->c[0]->siz+1;} } void travel(Tnode *x){ if (x!=null) q[++cnt]=x->val;else return; travel(x->c[0]);travel(x->c[1]); } int size(int p){return root[p]->siz;} void travel(int x){cnt=0;travel(root[x]);} void merge(int t1,int t2){ travel(t2); for (int i=1;i<=cnt;++i) insert(t1,q[i]); } }splay; struct Tsuffix_array{ int sum[maxn],sa[maxn],rank[maxn],tsa[maxn],trank[maxn]; bool cmp(int i,int j,int l){ if (i+l>n||j+l>n) return 0; return rank[i]==rank[j]&&rank[i+l]==rank[j+l]; } void suffix_sort(){ int m=255,p,i,j; for (i=0;i<=m;++i) sum[i]=0; for (i=1;i<=n;++i) ++sum[rank[i]=s[i]]; for (i=1;i<=m;++i) sum[i]+=sum[i-1]; for (i=n;i>=1;--i) sa[sum[rank[i]]--]=i; for (p=0,j=1;p<n;j<<=1,m=p){ for (p=0,i=n-j+1;i<=n;++i) tsa[++p]=i; for (i=1;i<=n;++i) if (sa[i]>j) tsa[++p]=sa[i]-j; for (i=0;i<=m;++i) sum[i]=0; for (i=1;i<=n;++i) ++sum[rank[tsa[i]]]; for (i=1;i<=m;++i) sum[i]+=sum[i-1]; for (i=n;i>=1;--i) sa[sum[rank[tsa[i]]]--]=tsa[i]; for (p=trank[sa[1]]=1,i=2;i<=n;++i) trank[sa[i]]=cmp(sa[i],sa[i-1],j)?p:++p; memcpy(rank,trank,sizeof(int)*(n+1)); } } int height[maxn]; void get_height(){ for (int h=0,i=1;i<=n;++i){ if (rank[i]==1) continue; for (h?--h:0;s[i+h]==s[sa[rank[i]-1]+h];++h); height[rank[i]]=h; } } int fa[maxn];PII t[maxn]; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} void get_ans(){ splay.clear(); for (int i=1;i<=n;++i){splay.insert(i,sa[i]);fa[i]=i;} for (int i=2;i<=n;++i) t[i-1]=make_pair(height[i],i); sort(t+1,t+n,greater<PII>()); for (int i=1;i<=n-1;++i){ int cur_height=t[i].first,cur_rank=t[i].second; if (!cur_height) break; int x=find(cur_rank),y=find(cur_rank-1); if (splay.size(x)>splay.size(y)) swap(x,y); splay.travel(x); for (int j=1;j<=cnt;++j){ int a=splay.greater(y,q[j]+l); int b=splay.less(y,cur_height+l+q[j]+1); ans+=(a+b-splay.size(y)); int c=splay.less(y,q[j]-l); int d=splay.greater(y,q[j]-cur_height-l-1); ans+=(c+d-splay.size(y)); } splay.merge(y,x);fa[x]=y; } } }SA; void init(){ scanf("%d%s",&l,s+1);n=strlen(s+1); SA.suffix_sort();SA.get_height(); } void work(){ SA.get_ans(); printf("%lld ",ans); } int main(){ init(); work(); return 0; }