后缀数组算法思路:乘数基数排序
数组: sa (第I个小后缀的下标),rk (第I个小后缀)。
时间复杂性: o(nLOGN ) o ) nlogn ) o ) nlogn ) )。
JSOI2007字符加密(排序循环移动位置) ) ) ) ) ) )。
题意:给出字符串abcde。 他有多个循环移动位置。 是abcde、bcdea、cdeab、…、ebacd。 把这些重新排列一下。 按从小到大的顺序输出每个字符串的最后一个字符。
思路:将字符串复制到abcdeabcde后,计算后缀数组。
# include bits/stdc.husingnamespacestd; const int N=2e5 5; char s[N]; int n,sa[N],rk[N],oldrk[N1],id[N],px[N],cnt[N]; BOOLCMP(intx,int y,int w ) returnoldrk [ x ]==oldrk [ y ] oldrk [ xw ]==oldrk [ yw ]; (}int main ) ) { int i,m=200,p,w; scanf('%s ',s 1 ); n=Strlen(s1; for(I=1; i=n; I ) s(In )=s ) I ); n*=2; for(I=1; i=n; I ) cnt[rk[i]=s[i]]; for(I=1; i=m; I ) cnt[i] =cnt[i-1]; for(I=n; i=1; -I ) sa[CNT[rk[I]]-- )=I; for(w=1; w=1,m=p ) {for(p=0,i=n; 合w; -I ) id[ p]=i; for(I=1; i=n; I ) if(sa[I]w ) id[ p]=sa[i] - w; memset(CNT,0,sizeof ) CNT ); for(I=1; i=n; I ) cnt[px[i]=rk[id[i]]]; for(I=1; i=m; I ) cnt[i] =cnt[i-1]; for(I=n; i=1; -I ) sa[CNT[px[I]]-- )=id[I]; memcpy(Oldrk,rk,sizeof ) rk ); for(p=0,i=1; i=n; I ) rk[sa[I]=CMP(sa[I]、sa[i-1]、w )? p: p; if(p==n ) for ) intI=1; i=n; I ) sa(rk ) I )=I; 黑; }for(I=1; i=n; I () if ) sa[I]n/2 ) continue; printf('%c ',s[sa[i] n/2 - 1] ); (Putchar ) 10; } [USACO06DEC]Milk Patterns (出现次数大于k的长子列) ) ) )。
想法:
子串是后缀的前缀。
因此,我们将先对后缀进行排序。 排序后相邻的k个后缀的最长共同前缀的长度是答案。 k个后缀的最长公共前缀的长度是k-1个连续的height阵列。 用单调的队列保护答案。
# include bits/stdc.husingnamespacestd; const int N=2e4 5; int s[N]; int n,ht[N],sa[N],rk[N],oldrk[N1],id[N],px[N],cnt[1000002]; BOOLCMP(intx,int y,int w ) returnoldrk [ x ]==oldrk [ y ] oldrk [ xw ]==oldrk [ yw ]; (}int main ) ) { int i,m=1000000,p,w,k; scanf('%d%d ),n,k ); k----; for(I=1; i=n; I ) scanf('%d ',s[i]; //后缀排序for(I=1; i=n; I ) cnt[rk[i]=s[i]]; for(I=1; i=m; I ) cnt[i] =cnt[i-1]; for(I=n; i=1; -I ) sa[CNT[rk[I]]-- )=I; for(w=1; w=1,m=p ) {for(p=0,i=n; 合w; -I ) id[ p]=i; for(I=1; i=n; I ) if(sa[I]w ) id[ p]=sa[i] - w; memset(CNT,0,sizeof ) CNT ); for(I=1; i=n; I ) cnt[px[i]=rk[id[i]]]; for(I=1; i=m; I ) cnt[i] =cnt[i-1]; for(I=n; i=1; -I ) sa[CNT[px[I]]-- )=id[I]; memcpy(Oldrk,rk,sizeof ) rk ); for(p=0,i=1; i=n; I ) rk[sa[I]=CMP(sa[I]、sa[i-1]、w )? p: p; if(p==n ) for ) intI=1; i=n; I ) sa(rk ) I )=I; 黑; }for(I=1,p=0; i=n; I ) if(p )--p; while(s[Ip]==s[sa[rk[I]-1]p] ) p; ht[rk[i]]=p; (//单调队列维持长度为k的区间的height最小值的最大值) /时,维持递增的数列int ans=0; dequeint q; for(I=1; i=n; I ) while(q.size ) ) q.front )=i-k ) q.pop_front ); while(q.size ) ht [ q.back ]=ht [ I ] ) q.pop_back; q.push_back(I; if(I=k ) ans=max ) ans,ht[q.front; }printf('%dn”,ans ); }