原来只会两个log平衡树合并。。后来围观claris在uoj群上秒题后会了这道题。
枚举A(B)的长度L,然后枚举i=kL,考虑前缀i,i+L和后缀i+1,i+L+1,求出前缀的lcp和后缀的lcp,然后合法的方案就在一个方案内。差分一下即可。注意要避免重复。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 30005
using namespace std;
int n,bin[25],lg2[N],q[N],sum[N],num[N]; char s[N];
struct saffix{
int a[N],sa[N],f[15][N],rnk[N<<1];
void getsa(){
int i,j,k,cnt;
memset(sum,0,sizeof(int)*26); memset(rnk+n+1,0,sizeof(int)*n);
for (i=1; i<=n; i++) sum[a[i]]++;
for (i=1; i<26; i++) sum[i]+=sum[i-1];
for (i=n; i; i--) sa[sum[a[i]]--]=i;
for (i=1,cnt=0; i<=n; i++){
if (i==1 || a[sa[i]]!=a[sa[i-1]]) cnt++;
rnk[sa[i]]=cnt;
}
for (k=1; cnt<n; k<<=1){
for (i=1; i<=k; i++) q[i]=n-k+i;
for (i=1,j=k; i<=n; i++) if (sa[i]>k) q[++j]=sa[i]-k;
memset(sum,0,sizeof(sum));
for (i=1; i<=n; i++) sum[rnk[i]]++;
for (i=1; i<=cnt; i++) sum[i]+=sum[i-1];
for (i=n; i; i--) sa[sum[rnk[q[i]]]--]=q[i];
for (i=1,cnt=0; i<=n; i++){
if (i==1 || rnk[sa[i]]!=rnk[sa[i-1]] || rnk[sa[i]+k]!=rnk[sa[i-1]+k]) cnt++;
q[sa[i]]=cnt;
}
for (i=1; i<=n; i++) rnk[i]=q[i];
}
}
void getf(){
int i,j,k;
for (i=1,k=0; i<=n; i++){
if (k) k--;
j=sa[rnk[i]-1];
while (i+k<=n && j+k<=n && a[i+k]==a[j+k]) k++;
f[0][rnk[i]]=k;
}
}
int lcp(int x,int y){
if (y>n) return 0;
x=rnk[x]; y=rnk[y]; if (x>y) swap(x,y);
int k=lg2[y-x];
return min(f[k][x+1],f[k][y-bin[k]+1]);
}
void pwk(){
int i,j;
for (i=1; i<=n; i++) a[i]=s[i]-'a';
getsa(); getf();
for (i=1; i<=14; i++)
for (j=1; j<=n; j++){
f[i][j]=f[i-1][j];
if (j+bin[i-1]<=n) f[i][j]=min(f[i][j],f[i-1][j+bin[i-1]]);
}
}
}ta,tb;
int main(){
int cas,i; scanf("%d",&cas);
bin[0]=1;
for (i=1; i<=14; i++){ bin[i]=bin[i-1]<<1; lg2[bin[i]]=i; }
for (i=2; i<=30000; i++) if (!lg2[i]) lg2[i]=lg2[i-1];
while (cas--){
scanf("%s",s+1); n=strlen(s+1);
int j,x,y;
ta.pwk();
for (i=1; i<=(n>>1); i++) swap(s[i],s[n-i+1]);
tb.pwk();
memset(sum,0,sizeof(sum)); memset(num,0,sizeof(num));
for (i=1; i<(n>>1); i++)
for (j=i; j+i<=n; j+=i){
x=max(j-i+1,j-tb.lcp(n-j+1,n-j-i+1)+1);
y=min(j,j-i+1+ta.lcp(j+1,j+i+1));
if ((x==10 || y==10) && i==2){
}
if (x<=y){
sum[x]++; sum[y+1]--;
num[x+(i<<1)]++; num[y+(i<<1)+1]--;
}
}
long long ans=0;
for (i=2; i<=n; i++){
sum[i]+=sum[i-1]; num[i]+=num[i-1];
ans+=sum[i]*num[i];
}
printf("%lld\n",ans);
}
return 0;
}
by lych
2016.8.4