后缀数组是一个处理字符串的有力工具,基本用途有模式串匹配和后缀最长公共前缀;例题
【JSOI 2007】【BZOJ 1031】字符加密ciper
后缀数组的躶体,现将字符串复制成环,然后输出 sa[i]<len 的 s[sa[i]−1] 即可,code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[250001];
int sa[250001];
int x[250001],y[250001],c[250001];
int n,maxm=0;
inline bool cmp(int *y, int a, int b, int k) {
int arank1 = y[a];
int brank1 = y[b];
int arank2 = a + k >= n ? -1 : y[a + k];
int brank2 = b + k >= n ? -1 : y[b + k];
return arank1 == brank1 && arank2 == brank2;
}
void build_sa()
{
int i,k;
for (i=0;i<maxm;++i) c[i]=0;
for (i=0;i<n;++i) c[x[i]=s[i]]++;
for (i=1;i<maxm;++i) c[i]+=c[i-1];
for (i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
for (k=1;k<=n;k<<=1)
{
int p=0;
for (i=n-k;i<n;++i) y[p++]=i;
for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
for (i=0;i<maxm;++i) c[i]=0;
for (i=0;i<n;++i) c[x[y[i]]]++;
for (i=1;i<maxm;++i) c[i]+=c[i-1];
for (i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for (i=1;i<n;++i)
x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?p-1:p++;
if (p>=n) break;
maxm=p;
}
}
int main()
{
int i;
scanf("%s",&s);
n=strlen(s);
for (i=0;i<n;++i)
{
maxm=max(maxm,(int)(s[i]));
s[i+n]=s[i];
}
n*=2; maxm++;
build_sa();
for (i=0;i<n;++i)
if (sa[i]<(n/2))
printf("%c",s[(sa[i]+(n/2)-1)%(n/2)]);
printf("\n");
}
【AHOI 2013】【BZOJ 3238】差异
题目要求求出:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 2100000000
#define mid (l+r)/2
#define lch i<<1,l,mid
#define rch i<<1|1,mid+1,r
using namespace std;
char s[500001];
int n,ans,ansi,maxm;
struct hp{
int minn,mini;
}seg[2000001];
struct he{
int l,r;
}range[500001];
int sa[500001],rank[500001],height[500001],x[500001],y[500001],c[500001];
long long pre[500001];
bool cmp(int *y,int i,int j,int k)
{
int a,b,c,d;
a=y[i]; b=y[j];
c=i+k>=n?-1:y[i+k]; d=j+k>=n?-1:y[j+k];
return a==b&&c==d;
}
void build_sa()
{
int i,j,k;
for (i=0;i<maxm;++i) c[i]=0;
for (i=0;i<n;++i) c[x[i]=s[i]]++;
for (i=1;i<maxm;++i) c[i]+=c[i-1];
for (i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
for (k=1;k<=n;k<<=1)
{
int p=0;
for (i=n-k;i<n;++i) y[p++]=i;
for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
for (i=0;i<maxm;++i) c[i]=0;
for (i=0;i<n;++i) c[x[y[i]]]++;
for (i=1;i<maxm;++i) c[i]+=c[i-1];
for (i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for (i=1;i<n;++i)
x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?p-1:p++;
if (p>=n) break;
maxm=p;
}
for (i=0;i<n;++i)
rank[sa[i]]=i;
k=0;
for (i=0;i<n;++i)
{
if (!rank[i]) continue;
if (k) k--;
j=sa[rank[i]-1];
while (s[i+k]==s[j+k]) k++;
height[rank[i]]=k;
}
}
void updata(int i)
{
seg[i].minn=min(seg[i<<1].minn,seg[i<<1|1].minn);
if (seg[i<<1].minn<=seg[i<<1|1].minn)
seg[i].mini=seg[i<<1].mini;
else
seg[i].mini=seg[i<<1|1].mini;
}
void build(int i,int l,int r)
{
if (l==r)
{
seg[i].minn=height[l];
seg[i].mini=l;
return;
}
build(lch); build(rch);
updata(i);
}
void query(int i,int l,int r,int x,int y)
{
if (x<=l&&y>=r)
{
if (ans>seg[i].minn)
{
ans=seg[i].minn;
ansi=seg[i].mini;
}
return;
}
if (x<=mid) query(lch,x,y);
if (y>mid) query(rch,x,y);
}
void make_range(int l,int r)
{
int t;
ans=inf;
if (l>=r) return;
query(1,0,n-1,l+1,r);
t=ansi;
range[ansi].l=l; range[ansi].r=r;
make_range(l,t-1);
make_range(t,r);
}
int main()
{
int i;
long long ans=0;
scanf("%s",&s);
n=strlen(s);
for (i=0;i<n;++i)
maxm=max(maxm,(int)(s[i]));
maxm++;
build_sa();
build(1,0,n-1);
make_range(0,n-1);
pre[0]=n-sa[0];
for (i=1;i<n;++i)
pre[i]=(long long)(pre[i-1]+n-sa[i]);
for (i=1;i<n;++i)
ans+=(pre[i-1]-pre[range[i].l-1])*(long long)(range[i].r-i+1)+(pre[range[i].r]-pre[i-1])*(long long)(i-range[i].l)-2*(long long)(height[i]*(long long)((range[i].r-i+1)*(i-range[i].l)));
printf("%lld\n",ans);
}