【后缀数组】[UVA10829]L-Gap substring
题目
分析,这道题很显然要找两个相同的字串,也就是两个后缀公共前缀,很自然地可以想到,可以使用后缀数组。
所谓的L-Gap字串,就是两个相同的字串,中间间隔了g个字符,所以,我们枚举这两个字串的长度l,然后看0和l,l和l*2…..分别从这两个位置向前和向后匹配,匹配的长度减去l就是这个位置对答案的贡献。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 50000*2
#define MAXC 128
#define Log 17
int array[4][MAXN+10],st[MAXN+10][Log+1],g,*sa,*nsa,*rk,*nrk,b[MAXN+10],n,na,m,T,height[MAXN+10],ans,cnt;
char s[MAXN+10];
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
void cal_sa(){
rk=array[0],nrk=array[1],sa=array[2],nsa=array[3];
int i,k;
rk[n]=nrk[n]=-1;
memset(b,0,sizeof b);
for(i=0;i<n;i++)
b[s[i]]++;
for(i=1;i<=MAXC;i++)
b[i]+=b[i-1];
for(i=0;i<n;i++)
sa[--b[s[i]]]=i;
for(rk[sa[0]]=0,i=1;i<n;i++){
rk[sa[i]]=rk[sa[i-1]];
if(s[sa[i]]!=s[sa[i-1]])
rk[sa[i]]++;
}
for(k=1;rk[sa[n-1]]<n-1;k<<=1){
for(i=0;i<n;i++)
b[rk[sa[i]]]=i;
for(i=n-1;i>=0;i--)
if(sa[i]>=k)
nsa[b[rk[sa[i]-k]]--]=sa[i]-k;
for(i=n-k;i<n;i++)
nsa[b[rk[i]]--]=i;
for(nrk[nsa[0]]=0,i=1;i<n;i++){
nrk[nsa[i]]=nrk[nsa[i-1]];
if(rk[nsa[i]]!=rk[nsa[i-1]]||rk[nsa[i]+k]!=rk[nsa[i-1]+k])
nrk[nsa[i]]++;
}
swap(sa,nsa);
swap(rk,nrk);
}
}
void read(){
Read(g);
scanf("%s",s);
na=strlen(s);
s[na]='$';
int i;
for(i=1;i<=na;i++)
s[na+i]=s[na-i];
n=(na<<1)|1;
s[n]=0;
}
void cal_height(){
int i,j,k=0;
for(i=0;i<n;i++)
if(!rk[i])
height[rk[i]]=0;
else{
if(k)
k--;
for(j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
height[rk[i]]=k;
}
}
void prepare(){
int i,j;
for(i=0;i<n;i++)
st[i][0]=height[i];
for(j=1;j<=Log;j++)
for(i=0;i<n;i++)
if(i+(1<<(j-1))<n)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int Get_st(int rk1,int rk2){
if(rk1>rk2)
swap(rk1,rk2);
int t=log2(rk2-rk1);
return min(st[rk1+1][t],st[rk2-(1<<t)+1][t]);
}
void solve(){
int i,j,k,t;
for(i=1;i<na;i++){
for(j=0;j<na&&j+i+g<na;j+=i){
k=i+j+g;
t=min(Get_st(rk[j],rk[k]),i);
t+=min(Get_st(rk[n-j],rk[n-k]),i-1);
ans+=max(t-i+1,0);
}
}
}
int main()
{
Read(T);
while(T--){
memset(st,0,sizeof st);
ans=0;
read();
cal_sa();
cal_height();
prepare();
solve();
printf("Case %d: %d\n",++cnt,ans);
}
}