后缀数组
#define SUFFIX_ARRAY_PFXDBL #ifdef SUFFIX_ARRAY_PFXDBL namespace SA{ /* Suffix Array, Prefix Doubling Method <SUBSCRIPT_START_FROM,SIZE> MAXN : Maximum length for string s : String for building suffix array <0,MAXN> t,t2,c : [Auxiliary] buffers <0,MAXN> n : Length of string sa : Suffix Array, Lexicographically ith suffix starts from. <0,MAXN> rank : Suffix Rank, rank of the suffix starts from i <0,MAXN> height : LCP of suffix starts from sa[i] and sa[i-1] <1,MAXN> build_sa(int m) : m is the size of character set("character" being 0~m-1), should set s and n previously. getHeight() : Calculate height and rank array accordingly. #define REP(i,t) for(int i = 0;i < t; i++) #define REP_R(i,t) for(int i = t-1;i >= 0; i--) #define REP_1(i,t) for(int i = 1;i <= t; i++) #define REP_1R(i,t) for(int i = t;i >= 1; i--) Time : O(nlogn) Space : 7n */ const int MAXN = 10005; char s[MAXN]; int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],rank[MAXN],height[MAXN],n; void build_sa(int m){ int *x = t,*y = t2; //第一次基数排序 REP(i, m) c[i] = 0; //重置排序数组 REP(i, n) c[x[i]=s[i]]++; //拷贝字符串内容到x缓冲区,并在基数排序数组中统计字符数量 REP_1(i, m-1) c[i] += c[i-1]; //基数排序数组求前缀和以算出排名 REP_R(i, n-1) sa[--c[x[i]]] = i; //从后往前顺次查询后缀的排名写入SA(字符相同的时候,长度小的靠前,长度大的靠后) //此时的x数组可以看成是保存了各个位置开始的后缀对应的第一基准 for(int k = 1;k <= n; k <<= 1){ //第k次基数排序,单组长度2^k int p = 0; //利用SA排序第二基准,y存储的是第二基准排序之后的后缀开始位置 for(int i = n-k;i < n; i++) y[p++] = i; //长度没达到k,这种只能看第一基准,第二基准视为0 REP(i, n) if(sa[i] >= k) y[p++] = sa[i]-k; //从前往后扫SA,即从字典序小的后缀开始扫,如果这个后缀的开始位置>=k的话, //这个后缀在sa中的结果实际上是i-k的第二基准 //排序第一基准 REP(i, m) c[i] = 0; //重置排序数组 REP(i, n) c[x[y[i]]]++; //按第二基准顺序读取第一基准进行统计 REP(i, m) c[i] += c[i-1];//基数排序数组求前缀和以算出排名 REP_R(i, n-1) sa[--c[x[y[i]]]] = y[i];//按第二基准从后往前顺次查询后缀的排名写入SA //准备下一次排序的第一基准序列x //第二基准排序结果y没有用了,上一次的第一基准序列x还有用,直接互换 swap(x, y); //现在y是上一次的第一基准序列 p = 1; x[sa[0]] = 0;//第一基准从0开始 //现在的sa是排好序的,从小到大查询,如果两项无法分出先后,就令成统一基准,否则基准自增 //如果两个后缀的第一关键字和第二关键字一样,说明他们的排名一样 REP_1(i, n-1) x[sa[i]] = ((y[sa[i-1]] == y[sa[i]]) && (y[sa[i-1]+k]==y[sa[i]+k]))? p-1 : p++; if(p >= n) break; //如果基准数已达n,说明排序完成,所有后缀已经分出先后 m = p; //下一轮排序的基准数是p } } void getHeight(){ int i,j,k = 0; REP(i, n) rank[sa[i]] = i; for(i = 0;i < n; height[rank[i++]] = k) for(k?k--:0,j = sa[rank[i]-1];s[i+k]==s[j+k];k++); return; } } #endif
┆ 凉 ┆ 暖 ┆ 降 ┆ 等 ┆ 幸 ┆ 我 ┆ 我 ┆ 里 ┆ 将 ┆ ┆ 可 ┆ 有 ┆ 谦 ┆ 戮 ┆ 那 ┆ ┆ 大 ┆ ┆ 始 ┆ 然 ┆
┆ 薄 ┆ 一 ┆ 临 ┆ 你 ┆ 的 ┆ 还 ┆ 没 ┆ ┆ 来 ┆ ┆ 是 ┆ 来 ┆ 逊 ┆ 没 ┆ 些 ┆ ┆ 雁 ┆ ┆ 终 ┆ 而 ┆
┆ ┆ 暖 ┆ ┆ 如 ┆ 地 ┆ 站 ┆ 有 ┆ ┆ 也 ┆ ┆ 我 ┆ ┆ 的 ┆ 有 ┆ 精 ┆ ┆ 也 ┆ ┆ 没 ┆ 你 ┆
┆ ┆ 这 ┆ ┆ 试 ┆ 方 ┆ 在 ┆ 逃 ┆ ┆ 会 ┆ ┆ 在 ┆ ┆ 清 ┆ 来 ┆ 准 ┆ ┆ 没 ┆ ┆ 有 ┆ 没 ┆
┆ ┆ 生 ┆ ┆ 探 ┆ ┆ 最 ┆ 避 ┆ ┆ 在 ┆ ┆ 这 ┆ ┆ 晨 ┆ ┆ 的 ┆ ┆ 有 ┆ ┆ 来 ┆ 有 ┆
┆ ┆ 之 ┆ ┆ 般 ┆ ┆ 不 ┆ ┆ ┆ 这 ┆ ┆ 里 ┆ ┆ 没 ┆ ┆ 杀 ┆ ┆ 来 ┆ ┆ ┆ 来 ┆