两道后缀数组的应用
POJ 3415求的是两个串的所有公共字串的个数
HDU 4416求的是两个串的所有不相同的公共字串的个数
POJ 3415
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define MAXN 200100
typedef long long ll;
using namespace std;
char r[MAXN];
int sa[MAXN];
int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
int height[MAXN],rk[MAXN];
inline bool cmp(int *r,int a,int b,int len){
return r[a]==r[b]&&r[a+len]==r[b+len];
}
void SA(int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++)
ws[i]=0;
for(i=0;i<n;i++)
ws[x[i]=r[i]]++;
for(i=1;i<m;i++)
ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)
sa[--ws[x[i]]]=i;
for(j=p=1;p<n;j<<=1,m=p){
for(p=0,i=n-j;i<n;i++)
y[p++]=i;
for(i=0;i<n;i++){
if(sa[i]>=j)
y[p++]=sa[i]-j;
}
for(i=0;i<m;i++)
ws[i]=0;
for(i=0;i<n;i++)
ws[wv[i]=x[y[i]]]++;
for(i=1;i<m;i++)
ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)
sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void Height(int n){
int i,j,k=0;
for(i=0;i<=n;i++) //这里sa[0]为‘\0’开始的子串
rk[sa[i]]=i;
for(i=0;i<n;height[rk[i++]]=k)
for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
}
int la;
int init(){
int i,j,len;
memset(height,0,sizeof(height));
scanf("%s",r);
len=strlen(r);
r[len]='$';
la=len;
scanf("%s",&r[len+1]);
return strlen(r);
}
int k;
int count(int num){
if(num<k) return 0;
else return num-k+1;
}
void solve(int n){
ll ans=0;
ll suma=0,sumb=0;
int sta[MAXN],top=0;
sta[0]=0;
ll ca[MAXN],cb[MAXN];
ca[1]=cb[1]=0;
for(int i=2;i<n;i++){
if(sa[i]<=la){
ca[i]=ca[i-1]+1;
cb[i]=cb[i-1];
}
else{
ca[i]=ca[i-1];
cb[i]=cb[i-1]+1;
}
}
for(int i=3;i<n;i++){
if(sa[i-1]<=la) suma+=(ll)count(height[i]);
else sumb+=(ll)count(height[i]);
sta[++top]=i-1;
while(top>=2 && height[sta[top]+1]<height[sta[top-1]+1]){
suma-=(ll)(count(height[sta[top-1]+1])-count(height[sta[top]+1]))*(ca[sta[top-1]]-ca[sta[top-2]]);
sumb-=(ll)(count(height[sta[top-1]+1])-count(height[sta[top]+1]))*(cb[sta[top-1]]-cb[sta[top-2]]);
sta[top-1]=sta[top--];
}
if(sa[i]<=la) ans+=sumb;
else ans+=suma;
}
printf("%lld\n",ans);
}
int main(){
int n;
while(scanf("%d",&k)){
if(k==0) break;
n=init();
SA(n+1,130);
Height(n);
solve(n+1);
}
}
HDU 4416
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 400100
char r[MAXN];
int hhh[MAXN];
int sa[MAXN];
int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
int height[MAXN],rank[MAXN];
int la,nn,t;
inline bool cmp(int *r,int a,int b,int len){
return r[a]==r[b]&&r[a+len]==r[b+len];
}
void SA(int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++)
ws[i]=0;
for(i=0;i<n;i++)
ws[x[i]=r[i]]++;
for(i=1;i<m;i++)
ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)
sa[--ws[x[i]]]=i;
for(j=p=1;p<n;j<<=1,m=p){
for(p=0,i=n-j;i<n;i++)
y[p++]=i;
for(i=0;i<n;i++){
if(sa[i]>=j)
y[p++]=sa[i]-j;
}
for(i=0;i<m;i++)
ws[i]=0;
for(i=0;i<n;i++)
ws[wv[i]=x[y[i]]]++;
for(i=1;i<m;i++)
ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)
sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void Height(int n){
int i,j,k=0;
for(i=1;i<=n;i++)
rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
void init(){
int i,j,nnn,n,tem;
scanf("%d",&nnn);
scanf("%s",r);
la=strlen(r);
r[la]='#';
tem=la+1;
for(i=1;i<=nnn;i++){
scanf("%s",&r[tem]);
n=strlen(&r[tem]);
r[n+tem]='#';
for(j=0;j<n;j++){
hhh[j+tem]=tem+n;
//printf("***%d := %d*****\n",tem+j,hhh[j+tem]);
}
tem+=n+1;
hhh[tem-1]=0;
//printf("***%d := %d*****\n",tem-1,hhh[tem-1]);
}
nn=tem;
}
void solve(int n){
long long sum=0;
int last=0,i,flag=0;
//printf("%s\n",r);
for(i=1;i<=n;i++){
if(sa[i]<la){
if(last==0){
sum+=la-sa[i]-min(height[i],la-sa[i]);
flag=sa[i]+min(height[i],la-sa[i])-1;
}
else if(last==1){
sum+=la-sa[i]-min(height[i],la-sa[i]);
flag=sa[i]+min(flag-sa[i-1]+1,min(height[i],la-sa[i]))-1;
/*if(min(height[i],la-sa[i])==0)
flag=sa[i]-1;
else if(flag>sa[i]+min(height[i],la-sa[i])-1)
flag=sa[i]+min(height[i],la-sa[i])-1;*/
}
last=1;
}
else{
if(last==1)
sum-=max(sa[i-1]+min(height[i],hhh[sa[i]]-sa[i])-1-flag,0);
last=0;
}
//printf("****%d %d %d %lld***\n",sa[i],min(height[i],hhh[sa[i]]-sa[i]),flag,sum);
}
printf("Case %d: %I64d\n",t,sum);
}
int main(){
int i,j,T,n;
scanf("%d",&T);
for(t=1;t<=T;t++){
memset(height,0,sizeof(height));
memset(r,'\0',sizeof(r));
init();
n=nn;
SA(n+1,130);
Height(n);
solve(n);
}
}