思路:这题和上一题SPOJ687的思路一样,也是枚举长度,再对于i和i+j+L向前向后匹配,但是这一题只能在后面接一个反串。
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> const int maxn=100010; using namespace std; int n,sum[maxn],t1[maxn],t2[maxn],sa[maxn],rank[maxn],h[maxn],st[maxn][20],L,len;char s[maxn];long long ans; void getsa(){ int *x=t1,*y=t2,m=255,p=0; for (int i=1;i<=n;i++) sum[x[i]=s[i]]++; for (int i=1;i<=m;i++) sum[i]+=sum[i-1]; for (int i=n;i;i--) sa[sum[x[i]]--]=i; for (int j=1;p<n;j<<=1,m=p){ p=0; for (int i=n-j+1;i<=n;i++) y[++p]=i; for (int i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j; memset(sum,0,sizeof(sum)); for (int i=1;i<=n;i++) sum[x[y[i]]]++; for (int i=1;i<=m;i++) sum[i]+=sum[i-1]; for (int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i]; swap(x,y),x[sa[1]]=p=1; for (int i=2;i<=n;i++){ if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j]) p++; x[sa[i]]=p; } } memcpy(rank,x,sizeof(rank)); } void geth(){ for (int i=1,j=0;i<=n;i++){ if (rank[i]==1) continue; while (s[i+j]==s[sa[rank[i]-1]+j]) j++; h[rank[i]]=j; if (j) j--; } } void getst(){ for (int i=1;i<=n;i++) st[i][0]=h[i]; for (int j=1;j<=19;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 getmin(int x,int y){ int l=rank[x],r=rank[y]; if (l>r) swap(l,r); l++;int k=log2(r-l+1); return min(st[l][k],st[r-(1<<k)+1][k]); } int main(){ scanf("%d%s",&L,s+1); len=strlen(s+1),s[n=len+1]=127; for (int i=len;i;i--) s[++n]=s[i];s[n+1]=0; getsa(),geth(),getst(); for (int i=1;i+i+L<=len;i++) for (int j=1;j<=len;j+=i){ int k=j+i+L,tmp=0; if (k<=len) tmp+=min(i,getmin(j,k)); if (j>=2) tmp+=min(i-1,getmin(n-j+2,n-k+2)); ans+=max(0,tmp-i+1); } printf("%lld ",ans); return 0; }