题意:有一种形如uvu形式的字符串,其中u是非空字符串,且V的长度正好为L,那么称这个字符串为L-Gap字符串
给出一个字符串S,以及一个正整数L,问S中有多少个L-Gap子串.
/* 这道题用到一个常用的技巧(虽然我这是第一次见)。 枚举U的长度,然后每隔U枚举i,然后确定j,则j一定在另一个U里面,有了i、j之后,向左向右扩展,看看能匹配多长。 */ #include<cstdio> #include<iostream> #include<cstring> #define N 600010 using namespace std; int t1[N],t2[N],c[N],s[N],sa[N],rk[N],height[N],n; int st[N][21],lg2[N]; char ch[N]; bool cmp(int *y,int a,int b,int k){ int a1=y[a],b1=y[b]; int a2=a+k<=n?y[a+k]:-1; int b2=b+k<=n?y[b+k]:-1; return a1==b1&&a2==b2; } void DA(){ int *x=t1,*y=t2,m=27; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[i]=s[i]]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i;i--) sa[c[x[i]]--]=i; for(int k=1,p=0;k<=n;k*=2,m=p,p=0){ for(int i=n-k+1;i<=n;i++) y[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[y[i]]]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i]; swap(x,y);p=1;x[sa[1]]=1; for(int i=2;i<=n;i++) if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p; else x[sa[i]]=++p; if(p>=n) break; } } void geth(){ for(int i=1;i<=n;i++) rk[sa[i]]=i; for(int i=1,j=0;i<=n;i++){ while(s[i+j]==s[sa[rk[i]-1]+j]) j++; height[rk[i]]=j; if(j) j--; } for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1; for(int i=1;i<=n;i++) st[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); } int query(int l,int r){ l=rk[l];r=rk[r]; if(l>r) swap(l,r); int k=lg2[r-l]; return min(st[l+1][k],st[r-(1<<k)+1][k]); } int main(){ int T;scanf("%d",&T); for(int cas=1;cas<=T;cas++){ long long ans=0;int G; scanf("%d%s",&G,ch+1); int len=strlen(ch+1); for(int i=1;i<=len;i++) s[i]=s[len*2-i+2]=ch[i]-'a'+1; s[len+1]=27;n=len*2+1; DA();geth(); for(int U=1;U*2+G<=len;U++) for(int i=1;i+U+G<=len;i+=U){ int j=i+U+G; if(s[i]!=s[j]) continue; int L=min(U,query(i,j))+min(U,query(len*2-i+2,len*2-j+2))-1;//分别为向右和向左扩展 if(L>=U) ans+=L-U+1; } cout<<"Case "<<cas<<": "<<ans<<endl; } return 0; }