First things first
这玩意似乎我17年搞过,但是现在毫无记忆qwq
用处是对后缀排序,和求LCS
正文
倍增法很好理解,运用基数排序,每次排序一倍长度的前缀
qwq
这点东西背板子比较好
详细解释留坑
Code (By Adscn in 2017) 因为是17年的所以非常naive
#include<bits/stdc++.h>
using namespace std;
#define File(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
#define T int
T get()
{
T xi=0;
bool f=0;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=1;
ch=getchar();
}
while(ch>='0'&&ch<='9')xi=xi*10+ch-48,ch=getchar();
if(f)xi=-xi;
return xi;
}
void put(T xi)
{
if(xi<0)putchar('-'),xi=-xi;
char p[sizeof(T)*2+1];
int cnt=0;
do p[cnt++]=xi%10+48,xi/=10; while(xi);
do putchar(p[--cnt]); while(cnt);
}
const int Size=1000001;
struct SuffixArray{
char s[Size];
int rank[Size],count[Size],sa[Size],rankx[Size],ranky[Size],height[Size],n;
void getrank()
{
int m=150;
n=strlen(s);
int *key1=rankx,*key2=ranky;
for(int i=0;i<=m;i++)count[i]=0;
for(int i=0;i<n;i++)count[key1[i]=s[i]]++;
for(int i=1;i<m;i++)count[i]+=count[i-1];
for(int i=n-1;i>=0;i--)sa[--count[key1[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++)key2[p++]=i;
for(int i=0;i<n;i++)if(sa[i]>=k)key2[p++]=sa[i]-k;
for(int i=0;i<=m;i++)count[i]=0;
for(int i=0;i<n;i++)count[key1[key2[i]]]++;
for(int i=1;i<m;i++)count[i]+=count[i-1];
for(int i=n-1;i>=0;i--)sa[--count[key1[key2[i]]]]=key2[i];
swap(key1,key2);
p=1,key1[sa[0]]=0;
for(int i=1;i<n;i++)key1[sa[i]]=(key2[sa[i-1]]==key2[sa[i]]&&key2[sa[i-1]+k]==key2[sa[i]+k])?p-1:p++;
if(p>=n)break;
m=p;
}
for(int i=0;i<n;i++)rank[sa[i]]=i;
}
void getheight()
{
n=strlen(s);
int k=0;
for(int i=0;i<n;i++)
{
k?k--:0;
int p=sa[rank[k]-1];
while(s[i+k]==s[p+k]&&(++k));
height[rank[i]]=k;
}
}
};
SuffixArray k;
int main()
{
#ifndef ONLINE_JUDGE
//File("");
#endif
cin>>k.s;
k.getrank();
for(int i=0;i<k.n;i++)printf("%d ",k.sa[i]+1);
return 0;
}
应用
先拿Anderson的用用Problem1
有一个字符串s,求它的子串中至少出现过两次的最长的子串。
Solution1
考虑height的定义:两个rank值相近的字符串的prefix,那么很显然这样子一定比rank值远一些的更优啊!
所以答案就是\(\max(height_i)(i∈(1,n))\)Problem2
有一个字符串s,求它的子串中至少出现过两次的最长的子串(不可重叠)。
Solution2
二分答案然后分成很多个集合就可以了。
Problem3
给定一个字符串s,求它不同的子串的个数。
Solution3
考虑一下每一个后缀可以提供\(len−len1\)个子串,然后考虑有\(height_i\)个重复了。
直接加起来就好了