字尾陣列及應用
阿新 • • 發佈:2018-12-31
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\)
直接加起來就好了